# I keep getting linker error, could you help me fix it?

**URL:** <https://discourse.cmake.org/t/i-keep-getting-linker-error-could-you-help-me-fix-it/10405>\
**Category:** Code\
**Tags:** os:linux\
**Created:** [March 19, 2024, 8:41am UTC](https://discourse.cmake.org/t/i-keep-getting-linker-error-could-you-help-me-fix-it/10405 "2024-03-19T08:41:18Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Shepard](https://discourse.cmake.org/user_avatar/discourse.cmake.org/shepard/32/4416_2.png) [@Shepard](https://discourse.cmake.org/u/Shepard)\
**Post date:** [March 19, 2024, 8:41am UTC](https://discourse.cmake.org/t/i-keep-getting-linker-error-could-you-help-me-fix-it/10405/1 "2024-03-19T08:41:18Z")

</div>

I can’t figure out why but I keep getting linker errors.

I followed/read several problems for example [this](https://stackoverflow.com/questions/13703647/how-to-properly-add-include-directories-with-cmake) and I can’t get it to work.

My root is as follows:

```auto
.
├── bin
├── CMakeLists.txt
├── external
│ ├── CMakeLists.txt
│ └── tinyformat.h
├── source
│ ├── CMakeLists.txt
│ ├── main.cpp
│ └── utils
│ ├── assert.cpp
│ ├── assert.hpp
│ ├── CMakeLists.txt
│ ├── config.hpp
│ ├── print.hpp
│ ├── timer.cpp
│ └── timer.hpp
└── tests
    ├── CMakeLists.txt
    └── test.cpp

```

# Also TLDR

I tried looking for repos with a similar (possible smarter) structure. If you find any, let me know and I will try to make that work.

# Code

In `timer.hpp` I have defined a class:

```auto
#pragma once

#include "config.hpp"
#include <chrono>
#include <iostream>
#include <string>
#include <vector>

namespace WingDesigner {
    /**
 * Simple timer class: add checkpoints throughout the code and measure execution time between them.
 */
    class Timer {
    protected:
        typedef std::chrono::steady_clock::time_point time_type;/// Time type.
        std::vector<std::string> m_Labels; /// List of checkpoint labels.
        std::vector<time_type> m_Times; /// List of checkpoint times.
       // and some methods...
    };
}

```

which is then implemented in `timer.cpp`.

In my `main.cpp` I want to create an instance of Timer and some `prn`statement which is a macro.

```auto
#include "utils/timer.hpp"
#include <iostream>
#include <omp.h>
#include <vector>
using namespace WingDesigner;

int main() {
  std::cout << "Hello, World!" << std::endl;

  Timer t;
  prn("Hi");

  return 0;
}

```

My `assert.hpp` also uses an external header from `external` directory.

```auto
/**
 * Implementation of custom assert and debug utilities.
 */

#pragma once
#include "config.hpp"
#include "print.hpp"
#include "tinyformat.h"

namespace WingDesigner {

// print macro
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL( __VA_ARGS__ , 5, 4, 3, 2, 1, 0)
#define VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define macro_dispatcher(func, ...) \
  macro_dispatcher_(func, VA_NUM_ARGS( __VA_ARGS__ ))
#define macro_dispatcher_(func, nargs) macro_dispatcher__(func, nargs)
#define macro_dispatcher__(func, nargs) func##nargs
#define addflag(a) \
  { std::cerr << "flags=[flags, " << (a) << "];" << std::endl; }
#define prnv2(a, b) \
  { std::cerr << a << " = " << (b) << ";" << std::endl; }
#define prnv1(a) \
  { std::cerr << #a << " = " << (a) << ";" << std::endl; }
/**
 * Prints a variable name and value to standard output. Can take one or two
 * parameters. Example: int a = 6; prn(a) // prints 'a = 6;' prn("value", a) //
 * prints 'value = 6;'
 */
#define prn(...) macro_dispatcher(prnv, __VA_ARGS__ )( __VA_ARGS__ )

using tinyformat::format;
using tinyformat::printf;

/// Namespace holding custom assert implementation.
namespace assert_internal {
/**
 * Actual assert implementation.
 * @param condition Condition to test, e.g.\ `n > 0`.
 * @param file File where the assertion failed.
 * @param func_name Function name where the assertion failed.
 * @param line Line on which the assertion failed.
 * @param message Message as specified in the `assert_msg` macro.
 * @param format_list List of format field values to pass to
 * `tinyformat::format` function.
 */
bool assert_handler_implementation(const char *condition, const char *file,
                                   const char *func_name, int line,
                                   const char *message,
                                   tfm::FormatListRef format_list);
/// Assert handler that unpacks varargs.
template <typename... Args>
bool assert_handler(const char *condition, const char *file,
                    const char *func_name, int line, const char *message,
                    const Args &...args) { // unpacks first argument
  tfm::FormatListRef arg_list = tfm::makeFormatList(args...);
  return assert_handler_implementation(condition, file, func_name, line,
                                       message, arg_list);
}
} // namespace assert_internal

#ifdef NDEBUG
#define assert_msg(cond, ...) ((void)sizeof(cond))
#else
/**
 * @brief Assert with better error reporting.
 * @param cond Conditions to test.
 * @param ... The second parameter is also required and represents the message
 * to print on failure. For every %* field in message one additional parameter
 * must be present.
 *
 * Example:
 * @code
 * assert_msg(n > 0, "n must be positive, got %d.", n);
 * @endcode
 */
#define assert_msg(cond, ...) \
  ((void)(!(cond) && \
          WingDesigner::assert_internal::assert_handler( \
              #cond, __FILE__ , __PRETTY_FUNCTION__ , __LINE__ , __VA_ARGS__ ) && \
          (assert(0), 1)))
// #cond, __FILE__ , __PRETTY_FUNCTION__ , __LINE__ , __VA_ARGS__ ) &&
// (exit(1), 1)))
#endif

/**
 * Prints given text in bold red.
 * @param s text to print.
 */
inline void print_red(const std::string &s) {
  std::cout << "\x1b[31;1m" << s << "\x1b[37;0m";
}
/**
 * Prints given text in bold white.
 * @param s text to print.
 */
inline void print_white(const std::string &s) {
  std::cout << "\x1b[37;1m" << s << "\x1b[37;0m";
}
/**
 * Prints given text in bold green.
 * @param s text to print.
 */
inline void print_green(const std::string &s) {
  std::cout << "\x1b[32;1m" << s << "\x1b[37;0m";
}

} // namespace WingDesigner

```

Note that my top level `CMakeLists.txt` is:

```auto
cmake_minimum_required(VERSION 3.22)
project(wingdesigner LANGUAGES CXX)

# Variables.
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(source)

# contains an "external" library we will link to
add_subdirectory(external)

# enable testing and define tests
enable_testing()
add_subdirectory(tests)

```

my `source/CMakeLists.txt` is:

```auto
add_executable(wingdesigner main.cpp)

add_subdirectory(utils)

target_link_libraries(wingdesigner
        PRIVATE
        tinyformat
        utils
)

```

my `source/utils//CMakeLists.txt`is:

```auto
add_library(assert "")
target_sources(assert
        PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}/assert.cpp
        PUBLIC
        ${CMAKE_CURRENT_LIST_DIR}/assert.hpp
)
target_include_directories(assert
        PUBLIC
        ${CMAKE_CURRENT_LIST_DIR}
)

add_library(timer
        ${CMAKE_CURRENT_LIST_DIR}/timer.hpp
        ${CMAKE_CURRENT_LIST_DIR}/timer.cpp)
target_link_libraries(timer assert)

```

and finally my `external/CMakeLists.txt` is:

```auto
add_library(tinyformat "")

target_include_directories(tinyformat
        PRIVATE
        include
)

```

# The error

No matter what I try I get the following error:

```auto
CMake Error at external/CMakeLists.txt:1 (add_library):
  No SOURCES given to target: tinyformat

```

but there aren’t any sources, just a header.

Is there a better way to do this?

---

<div class="post-metadata">

**Author:** ![retif](https://discourse.cmake.org/user_avatar/discourse.cmake.org/retif/32/1776_2.png) [@retif](https://discourse.cmake.org/u/retif)\
**Post date:** [March 19, 2024, 9:02am UTC](https://discourse.cmake.org/t/i-keep-getting-linker-error-could-you-help-me-fix-it/10405/2 "2024-03-19T09:02:31Z")

</div>

> ```sh
> No SOURCES given to target: tinyformat
> 
> ```

Looks like that library needs to be an [INTERFACE library](https://cmake.org/cmake/help/latest/command/add_library.html#interface) (_also known as header-only library_):

```auto
add_library(tinyformat INTERFACE) # also no need to put empty quotes here

```

Unrelated, but likely also a (_potential_) issue is this block:

> ```auto
> target_include_directories(tinyformat
> PRIVATE
> include
> )
> 
> ```

There is no `include` folder inside `external` folder (_or anywhere in your project_), so this statement doesn’t do anything useful. In addition, there is no `PUBLIC`/`INTERFACE` scope there, so your other targets might still not discover `tinyformat`’s headers. Crudely scratching on a napkin, it should look like this instead:

```auto
target_include_directories(tinyformat
    INTERFACE
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
        #$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> # if also you intend to install it and make a relocatable package later
)

```

---

<div class="post-metadata">

**Author:** ![Shepard](https://discourse.cmake.org/user_avatar/discourse.cmake.org/shepard/32/4416_2.png) [@Shepard](https://discourse.cmake.org/u/Shepard)\
**Post date:** [March 19, 2024, 9:25am UTC](https://discourse.cmake.org/t/i-keep-getting-linker-error-could-you-help-me-fix-it/10405/3 "2024-03-19T09:25:03Z")

</div>

> [@retif](#):
>
> ```auto
> target_include_directories(tinyformat
> INTERFACE
> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
> #$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> # if also you intend to install it and make a relocatable package later
> )
> 
> ```

That helped a lot. Also explained some things I did not understand.

However, the linker now complains about the `utils`, saying

```auto
/usr/bin/ld: cannot find -lutils: No such file or directory
collect2: error: ld returned 1 exit status
gmake[3]: *** [source/CMakeFiles/wingdesigner.dir/build.make:97: source/wingdesigner] Error 1
gmake[2]: *** [CMakeFiles/Makefile2:153: source/CMakeFiles/wingdesigner.dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:160: source/CMakeFiles/wingdesigner.dir/rule] Error 2
gmake: *** [Makefile:134: wingdesigner] Error 2

```

And I again don’t see how as I added the sub directory and link to libraries in my `source/CMakeLists.txt`:

```auto
add_executable(wingdesigner main.cpp)

add_subdirectory(utils)

target_link_libraries(wingdesigner
        PRIVATE
        tinyformat
        utils
)

```

---

<div class="post-metadata">

**Author:** ![retif](https://discourse.cmake.org/user_avatar/discourse.cmake.org/retif/32/1776_2.png) [@retif](https://discourse.cmake.org/u/retif)\
**Post date:** [March 19, 2024, 9:31am UTC](https://discourse.cmake.org/t/i-keep-getting-linker-error-could-you-help-me-fix-it/10405/4 "2024-03-19T09:31:37Z")

</div>

There is no `add_library(utils)` anywhere, as far as I can see, so that error makes sense. I would guess that you confused the linking targets here:

```cmake
target_link_libraries(wingdesigner
    PRIVATE
        tinyformat
        # utils # there is no such target
        assert # is that what you wanted to link from utils?
        timer # is that what you wanted to link from utils?
)

```

---

<div class="post-metadata">

**Author:** ![Shepard](https://discourse.cmake.org/user_avatar/discourse.cmake.org/shepard/32/4416_2.png) [@Shepard](https://discourse.cmake.org/u/Shepard)\
**Post date:** [March 19, 2024, 9:42am UTC](https://discourse.cmake.org/t/i-keep-getting-linker-error-could-you-help-me-fix-it/10405/5 "2024-03-19T09:42:49Z")

</div>

Crap, you are correct. I think I need to go to bed for a moment …

But before that, fixing the target\_link\_libraries as you suggested, results in all sorts of assert.hpp linker errors:

```auto
/usr/bin/ld: utils/libtimer.a(timer.cpp.o): in function `bool WingDesigner::assert_internal::assert_handler<int, int>(char const*, char const*, char const*, int, char const*, int const&, int const&)':
/home/mjancic/Documents/wingdesigner++/source/utils/assert.hpp:57: undefined reference to `WingDesigner::assert_internal::assert_handler_implementation(char const*, char const*, char const*, int, char const*, tinyformat::FormatList const&)'
/usr/bin/ld: /home/mjancic/Documents/wingdesigner++/source/utils/assert.hpp:57: undefined reference to `WingDesigner::assert_internal::assert_handler_implementation(char const*, char const*, char const*, int, char const*, tinyformat::FormatList const&)'
/usr/bin/ld: /home/mjancic/Documents/wingdesigner++/source/utils/assert.hpp:57: undefined reference to `WingDesigner::assert_internal::assert_handler_implementation(char const*, char const*, char const*, int, char const*, tinyformat::FormatList const&)'
/usr/bin/ld: utils/libtimer.a(timer.cpp.o): in function `bool WingDesigner::assert_internal::assert_handler<char const*, std::vector<std:: __cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__ cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >(char const*, char const*, char const*, int, char const*, char const* const&, std::vector<std:: __cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__ cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&)':
/home/mjancic/Documents/wingdesigner++/source/utils/assert.hpp:57: undefined reference to `WingDesigner::assert_internal::assert_handler_implementation(char const*, char const*, char const*, int, char const*, tinyformat::FormatList const&)'
/usr/bin/ld: utils/libtimer.a(timer.cpp.o): in function `bool WingDesigner::assert_internal::assert_handler<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(char const*, char const*, char const*, int, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
/home/mjancic/Documents/wingdesigner++/source/utils/assert.hpp:57: undefined reference to `WingDesigner::assert_internal::assert_handler_implementation(char const*, char const*, char const*, int, char const*, tinyformat::FormatList const&)'
collect2: error: ld returned 1 exit status
gmake[3]: *** [source/CMakeFiles/wingdesigner.dir/build.make:100: source/wingdesigner] Error 1
gmake[2]: *** [CMakeFiles/Makefile2:154: source/CMakeFiles/wingdesigner.dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:161: source/CMakeFiles/wingdesigner.dir/rule] Error 2
gmake: *** [Makefile:134: wingdesigner] Error 2

```

I feel totally incompetent when it comes to linker errors… All references from that hpp seem to be undefined. Would you have any ideas?
