CMake导入图书馆目标给予未定义给予未定义的符号在Windows上

问题描述:

我试图导入libuv到我的CMake项目,所以我可以链接它。我从here安装libuv 1.12.0,并将其放入C:\Program Files\libuv\CMake导入图书馆目标给予未定义给予未定义的符号在Windows上

project(tls-server LANGUAGES C) 
set(LIBUV_ROOT_DIR "C:\\Program Files\\libuv") 
add_library(libuv SHARED IMPORTED) 
set_property(TARGET libuv PROPERTY IMPORTED_LOCATION "${LIBUV_ROOT_DIR}\\libuv.dll") 
set_property(TARGET libuv PROPERTY IMPORTED_IMPLIB "${LIBUV_ROOT_DIR}\\libuv.lib") 
add_executable(tls-server "${CMAKE_SOURCE_DIR}/src/main.c") 
target_link_libraries(tls-server libuv) 

然而,鉴于上面的代码我仍然得到在Visual Studio中未定义符号错误:

Error message

我该如何解决这个问题?我相信这些路径都是正确的。我也在使用Windows 10.

+2

你**不能**在MinGW上使用'.lib'文件。 '.lib'用于Visual Studio编译器和链接器,但MinGW及其gcc需要'.a'(或'.dll.a')。使用纯C语言,可以从'.def'文件创建'.a'。 – Tsyvarev

+0

@Tsyvarev我明白了。不过,使用Visual Studio生成器也会出现同样的错误。 – HexCoder

我终于设法解决了这个问题。

首先,我从目标库(libuv)重新安装了二进制文件。然后,我确定我的cmake正在使用cmake -G "Visual Studio 14 2015 Win64"生成x64项目文件。这足以摆脱未定义的符号错误。然后,我需要做的就是将libuv.dll文件复制到可执行文件所在的目录中,并且一切正常。

如果有人知道这个错误发生的原因,请发表评论,以便将来帮助其他人更好地指出错误的原因。

千万不要在CMake中硬编码像这样的库路径或名称。

改为使用find_library命令,如果提供的库存在问题,它可以很好地通知您。

特别是在Windows上,因为系统上没有默认位置(类似于* nix系统上的/usr/local/lib),所以您可能需要为库的位置提供额外的自定义点。我个人比较喜欢使用环境变量这一点,但一个正常的CMake的选项也会做:

project(tls-server LANGUAGES C) 

find_library(LIBUV_LIBRARIES NAMES uv libuv 
    HINTS $ENV{LIBUV_ROOT}) 

add_executable(tls-server ${PROJECT_SOURCE_DIR}/src/main.c) 
target_link_libraries(tls-server ${LIBUV_LIBRARIES}) 

注意CMake的一般永远没有复制运行时依赖于正确的位置的呵护!也就是说,如果libuv被构建为.dll,则在运行程序时必须确保.dll处于正确的路径中。

你当然可以在CMake中手动插入一个拷贝命令来获取所有的dll,但这可能非常麻烦。不幸的是,现在还没有更好的解决方案来解决这个问题。

在这里使用导入的目标是可能的,但如果您需要将更复杂的属性传递给相关目标,那么只能取得成效。根据我的经验,如果依赖项提供fully-fledged package config file,则导入的目标效果最佳。手动编写导入的目标在增加复杂性方面往往不值得。

+0

这篇文章如何帮助**问题**(“未定义的参考”)? *改进问题中的代码是好意,但这不是*答案帖子*的主要目的。最近我在meta上看到了相关的问题。 – Tsyvarev

+0

@Tsyvarev未定义的引用不会被检测到,因为CMake不检查硬编码路径。通过改进代码,潜在的问题被解决为一种副作用,这是一种比痛苦地调试问题更好的方法,同时让破碎的CMake保持原样。 StackOverflow不是免费的调试服务。 – ComicSansMS

+0

*有效*您的代码**在问题文章中完成相同的**(至少对于Visual Studio)。指定* HINTS *或* PATHS *只是硬编码路径的跨平台方式:这只允许自动选择库的前缀/后缀。 (假设您没有安装该库的系统)。 'StackOverflow不是免费的调试服务。“ - 这是针对”一堆代码没有任何评论“的情况。实际上,我猜想有关SO的更多90%的问题关于检测现有代码中的问题。 – Tsyvarev