Cmake target_link_libraries not linking my library
For the original CMakeLists.txt file, the problem is not with target_link_libraries but with add_executable
add_executable(uart ${uart_SRCS})
where did you set your uart_SRCS variable? Do you have
set(uart_SRCS src/blahblah.cpp src/somethingblahblah.cpp)
I think you might misunderstand what add_subdirectory does. It does not add the source files inside. It tells CMake to descend into that folder and look for another CMakeLists.txt. You typically use it when you have a sub-project inside of your project folder.
If you have many source files which you don't want to manually set, you can also do
file(GLOB uart_SRCS src/*.cpp src/*.c)
The downside is you need to manually re-run CMake in order for it to detect new files. See Jack's comment on why this might not be what you want to use.
Your CMakeLists.txt will most likely be
project(uart)
find_package(Qt4 REQUIRED)
include (${QT_USE_FILE})
find_package(KDE4 REQUIRED)
include (KDE4Defaults)
include_directories( ${KDE4_INCLUDES} ${QT_INCLUDES} src/include src/include/QSerialDevice )
link_directories(/usr/lib)
file(GLOB uart_SRCS src/*.cpp src/*.h)
file(GLOB uart_HDRS include/*.h include/QSerialDevice/*.h)
find_library(SERIALDEVICE_LIB qserialdeviced)
add_executable(uart ${uart_SRCS} ${uart_HDRS})
target_link_libraries(uart ${SERIALDEVICE_LIB} ${QT_LIBRARIES})
j4x
I believe I have climbed as many steps as possible in C++ programming a few years ago when I decided to switch career from any-level-developer to FAE in Embedded Systems. Five years later I may have to look for updates but having to keep my kids fed might impose a barrier... Ok. I can take any free lancing from Embedded Systems to Expert Systems and Data/Signal/Image Processing if it makes everybody happy.
Updated on July 09, 2022Comments
-
j4x almost 2 years
I'll begin stating that I'm almost complete dumb in Cmake matter.
I have the following
CMakeLists.txt
for a Kdevelop 4.1 project:project(uart) find_package(KDE4 REQUIRED) include (KDE4Defaults) include_directories( ${KDE4_INCLUDES} ${QT_INCLUDES} src/include src/include/QSerialDevce ) add_subdirectory(doc) add_subdirectory(src) add_subdirectory(icons) link_directories(/usr/lib) find_library(SERIALDEVICE_LIB qserialdeviced) add_executable(uart ${uart_SRCS}) target_link_libraries(uart ${SERIALDEVICE_LIB})
When I try to build my project I see:
uart/build> make -j2 -- Found Qt-Version 4.6.3 (using /usr/bin/qmake-qt4) -- Found X11: /usr/lib64/libX11.so -- Found KDE 4.5 include dir: /usr/include/kde4 -- Found KDE 4.5 library dir: /usr/lib64/kde4/devel -- Found the KDE4 kconfig_compiler4 preprocessor: /usr/bin/kconfig_compiler4 -- Found automoc4: /usr/bin/automoc4 CMake Error at CMakeLists.txt:16 (add_executable): add_executable called with incorrect number of arguments CMake Error: Attempt to add link library "/usr/lib/libqserialdeviced.so" to target "uart" which is not built by this project. -- Configuring incomplete, errors occurred! make: *** [cmake_check_build_system] Error 1 *** Failed ***
Everything I read says that
add_executable
andtarget_link_libraries
should look like the last two lines of my file:add_executable(uart ${uart_SRCS}) target_link_libraries(uart ${SERIALDEVICE_LIB})
If I change those two lines of
CMakeLists.txt
leaving it as:project(uart) find_package(KDE4 REQUIRED) include (KDE4Defaults) include_directories( ${KDE4_INCLUDES} ${QT_INCLUDES} src/include src/include/QSerialDevce ) add_subdirectory(doc) add_subdirectory(src) add_subdirectory(icons) link_directories(/usr/lib) find_library(SERIALDEVICE_LIB qserialdeviced) target_link_libraries(${SERIALDEVICE_LIB})
I see:
uart/build> make -j2 -- Found Qt-Version 4.6.3 (using /usr/bin/qmake-qt4) -- Found X11: /usr/lib64/libX11.so -- Found KDE 4.5 include dir: /usr/include/kde4 -- Found KDE 4.5 library dir: /usr/lib64/kde4/devel -- Found the KDE4 kconfig_compiler4 preprocessor: /usr/bin/kconfig_compiler4 -- Found automoc4: /usr/bin/automoc4 -- Configuring done -- Generating done -- Build files have been written to: uart/build [ 11%] Built target doc-handbook [ 11%] Built target uart_automoc Linking CXX executable uart CMakeFiles/uart.dir/uart.o: In function `uart::setupSerial()': uart/src/uart.cpp:126: undefined reference to `AbstractSerial::AbstractSerial(QObject*)' CMakeFiles/uart.dir/uart.o: In function `uart::setupEnumerator()': uart/src/uart.cpp:108: undefined reference to `SerialDeviceEnumerator::SerialDeviceEnumerator(QObject*)' CMakeFiles/uart.dir/uart.o: In function `uart::setupSerial()': uart_/uart/src/uart.cpp:136: undefined reference to `AbstractSerial::enableEmitStatus(bool)' CMakeFiles/uart.dir/uart.o: In function `uart::setupEnumerator()': uart_/uart/src/uart.cpp:112: undefined reference to `SerialDeviceEnumerator::setEnabled(bool)' collect2: ld returned 1 exit status make[2]: *** [src/uart] Error 1 make[1]: *** [src/CMakeFiles/uart.dir/all] Error 2 make: *** [all] Error 2 *** Failed ***
That clearly shows that
target_link_libraries
is not linking myqserialdeviced
.qserialdeviced
is at/usr/lib/libqserialdeviced.so.1.0.0
, correctly simlinked to/usr/lib/libqserialdeviced.so
and easily found if I manually add it in the Makefile.I obviously tried:
target_link_libraries(-lqserialdeviced)
with no change.
I also tried:
if ("${SERIALDEVICE_LIB}" STREQUAL "SERIALDEVICE_LIB-NOTFOUND") message(FATAL_ERROR "'qserialdeviced' wasn't found!") else() message("'qserialdeviced' found: " ${SERIALDEVICE_LIB}) endif ()
But this test succeeds. The library is found:
'qserialdeviced' found: /usr/lib/libqserialdeviced.so
Can anybody please help me to understand what happens here?
I am using Linux Fedora 13, cmake version 2.8.0, gcc (GCC) 4.4.5 20101112 (Red Hat 4.4.5-2) and kdevelop-4.1.0-1.fc13.x86_64.
Thanks i advance.
EDIT:
As suggested by @DatChu, I split my
CMakeLists.txt
across my subdirectories and everything makes sense to me now.Thanks everbody!
-
j4x about 13 yearsNo, I haven't set it, but tried to do something like
add_executable(uart src/main.cpp src/uart.cpp ...)
. I stopped because I find no much clever to repeat the names of all source files afteradd_subdirectory(src)
. Is there a better way of doing this? I must mention had erros even when I tried adding all the ".cpp" files manually. If you want, I can put the error in my post. Thanks. -
Dat Chu about 13 yearsIf you could update the original CMakeLists.txt with what you have right now + the files in your project, I can suggest what you need for CMake
-
Jack Kelly about 13 yearsPlease don't recommend the use of
file(GLOB ...)
: cmake.org/pipermail/cmake/2010-July/037984.html and cmake.org/pipermail/cmake/2010-September/039562.html -
Dat Chu about 13 years@Jack: Aside from the downside of CMake not detecting file changes, is there another reason against file(GLOB ...)?
-
Jack Kelly about 13 years@Dat Chu: From the top of my head: you run the risk of accidentally adding files to targets that don't need them. Because CMake doesn't share object files between targets, this always adds redundant compilation, lengthening the build time. Besides, once a project's reasonably mature, new files don't come along all that often.
-
Dat Chu about 13 years@Jack Kelly: Thanks. The way that I structure my project has no extra files in each folder. Plus, the argument of lacking of file changes when the project matures go both ways. I have updated my answer to note this.
-
j4x about 13 yearsI'm starting to understand what you all are saying. It reminds me one episode where Simpson's dog began to understand what people say. Unfortunately I'll have to wait til tomorrow to give a new try. Thanks people!
-
j4x about 3 yearsHave you declared your "c" functions (in your ".h") inside
#if defined(__cplusplus) extern "C"
? isocpp.org/wiki/faq/mixing-c-and-cpp#include-c-hdrs-personal -
skittlebiz about 3 yearsthey are only declared inside extern (without the "C"). Adding "C" will require the c files to be compiled with a C++ compiler, hence somewhat reiterating my "solution." (Also, rather than changing the filename to end in cpp, I believe you can also change a file's property by using: set_source_files_properties(file0.c file1.c PROPERTIES LANGUAGE CXX) )
-
j4x about 3 yearsNo, you don't. The
#ifdef
directives in the example I gave you take care of this. You can use either C or C++ compiler on your headers. Furthermore, why do you need to declare a function as pureextern
in your header?