【问题标题】:Cmake target_link_libraries not linking my libraryCmake target_link_libraries 没有链接我的库
【发布时间】:2011-07-20 17:10:56
【问题描述】:

我将开始声明我在 Cmake 问题上几乎完全是哑巴。

我有以下CMakeLists.txt 用于 Kdevelop 4.1 项目:

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})

当我尝试构建我的项目时,我看到:

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 ***

我读到的所有内容都说add_executabletarget_link_libraries 应该看起来像我文件的最后两行:

add_executable(uart ${uart_SRCS})
target_link_libraries(uart ${SERIALDEVICE_LIB})

如果我更改CMakeLists.txt 的这两行,则将其保留为:

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})

我明白了:

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 ***

这清楚地表明target_link_libraries 没有链接我的qserialdeviced

qserialdeviced 位于 /usr/lib/libqserialdeviced.so.1.0.0,正确 sim 链接到 /usr/lib/libqserialdeviced.so,如果我在 Makefile 中手动添加它很容易找到。

我显然试过了:

target_link_libraries(-lqserialdeviced)

没有变化。

我也试过了:

if ("${SERIALDEVICE_LIB}" STREQUAL "SERIALDEVICE_LIB-NOTFOUND")
    message(FATAL_ERROR "'qserialdeviced' wasn't found!")
else()
    message("'qserialdeviced' found: " ${SERIALDEVICE_LIB})
endif ()

但是这个测试成功了。图书馆找到了:

'qserialdeviced' found: /usr/lib/libqserialdeviced.so

谁能帮我理解这里发生了什么?

我正在使用 Linux Fedora 13、cmake 版本 2.8.0、gcc (GCC) 4.4.5 20101112 (Red Hat 4.4.5-2) 和 kdevelop-4.1.0-1.fc13.x86_64。

谢谢我提前。


编辑:

按照@DatChu 的建议,我将CMakeLists.txt 拆分到我的子目录中,现在一切对我来说都有意义。

谢谢大家!

【问题讨论】:

    标签: c++ linux linker cmake kdevelop


    【解决方案1】:

    对于原始的 CMakeLists.txt 文件,问题不在于 target_link_libraries 而在于 add_executable

    add_executable(uart ${uart_SRCS})
    

    你在哪里设置你的 uart_SRCS 变量?你有吗

    set(uart_SRCS src/blahblah.cpp src/somethingblahblah.cpp)
    

    我认为您可能误解了 add_subdirectory 的作用。它不会在里面添加源文件。它告诉 CMake 进入该文件夹并寻找另一个 CMakeLists.txt。当您的项目文件夹中有子项目时,通常会使用它。

    如果你有很多源文件不想手动设置,你也可以这样做

    file(GLOB uart_SRCS src/*.cpp src/*.c)
    

    缺点是您需要手动重新运行 CMake 才能检测到新文件。请参阅 Jack 关于为什么这可能不是您想要使用的评论。

    您的 CMakeLists.txt 很可能是

    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})
    

    【讨论】:

    • 不,我没有设置它,但尝试做类似add_executable(uart src/main.cpp src/uart.cpp ...) 的事情。我停下来是因为我发现在add_subdirectory(src) 之后重复所有源文件的名称并不聪明。有没有更好的方法来做到这一点?即使我尝试手动添加所有“.cpp”文件,我也必须提到有错误。如果你愿意,我可以把错误放在我的帖子里。谢谢。
    • @Dat Chu:从我的脑海中浮出水面:您冒着意外将文件添加到不需要它们的目标的风险。因为 CMake 不会在目标之间共享目标文件,所以这总是会增加冗余编译,从而延长构建时间。此外,一旦项目相当成熟,新文件就不会经常出现。
    • @Jack Kelly:谢谢。我构建项目的方式在每个文件夹中都没有额外的文件。另外,当项目成熟时缺少文件更改的说法是双向的。我已经更新了我的答案来说明这一点。
    • 我开始明白你们在说什么了。这让我想起了辛普森的狗开始理解人们所说的话的一集。不幸的是,我必须等到明天再试一次。谢谢大家!
    【解决方案2】:

    这并不是一个真正的直接解决方案,但是我遇到了“未定义引用”错误(之前通过链接适当的库解决了,但在这种情况下不是),直到我刚刚发现一些东西 - 与 c 不兼容以某种方式与cpp。定义这些引用函数的文件位于 .c 文件中(默认 cmake 将使用 C 编译器进行编译。)而我引用这些函数的文件是 .cpp 文件(使用 g++ 编译器或任何您的环境 c++ 编译器)。一旦我将 .c 文件更改为 .cpp ,“未定义的引用”错误就消失了。上面看起来你的 uart 文件是 .cpp,但也许检查一下其他文件是什么,然后试试这个方法。这可能不是合适的解决方案,甚至根本不是一个解决方案,但这可能会让您度过一天并继续前进。

    【讨论】:

    • 您是否在#if defined(__cplusplus) extern "C" 中声明了您的“c”函数(在您的“.h”中)? isocpp.org/wiki/faq/mixing-c-and-cpp#include-c-hdrs-personal
    • 它们只在外部声明(没有“C”)。添加“C”将需要使用 C++ 编译器编译 c 文件,因此在某种程度上重申了我的“解决方案”。 (另外,除了将文件名更改为以 cpp 结尾,我相信您还可以使用以下方法更改文件的属性: set_source_files_properties(file0.c file1.c PROPERTIES LANGUAGE CXX) )
    • 不,你没有。我给你的例子中的#ifdef 指令会处理这个问题。您可以在标头上使用 C 或 C++ 编译器。此外,为什么你需要在你的头文件中将一个函数声明为纯extern
    猜你喜欢
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    • 2021-08-29
    • 2014-11-20
    • 2016-09-06
    • 2019-03-09
    相关资源
    最近更新 更多