CMake:包含目录的排序(如何混合基于系统和用户的包含路径?)
我有一个 CMake 项目,其中包含并链接两个库,例如 A
和 B
(实际上它不止两个,其中一个是 boost 的东西,但这并不这里并不重要)。两者都通过 FindSomething.cmake 脚本定位,这些脚本(正确地)填充标准 CMake 变量,以便通过添加包含目录
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${B_INCLUDE_DIRS})
并稍后通过完成链接
TARGET_LINK_LIBRARIES(mytarget ${A_LIBRARIES} ${B_LIBRARIES})
现在,问题是这两个库都可以驻留在基于用户的位置或系统目录(顺便说一下,我在 Linux 上,CMake 2.8.2) - 或两者兼而有之。假设 A
仅在 $HOME/usr/include
和 $HOME/usr/lib
中,而 B
( boost 在我的例子中)驻留在系统路径(/usr/include
和 /usr/lib
)和基于用户的路径中 - 在不同的版本中。可以使用查找脚本来查找系统或基于用户的库 B
,这是可行的。
当我想从系统路径链接 B
时,麻烦就开始了。${B_INCLUDE_DIRS}
和 ${B_LIBRARIES}
正确指向系统标头和库的范围位置。但仍然有 ${A_INCLUDE_DIRS}
指向非系统包含目录,最终库 B
的标头也从此位置获取,而 B
的链接code>B 使用系统路径中的版本(通过 ${B_LIBRARIES}
),这会导致冲突,即链接错误。
更改 INCLUDE_DIRECTORIES 语句的顺序似乎没有改变任何内容。我通过目标文件上的 nm --line-numbers 检查了导致链接错误的符号的来源。
我能做些什么?是否有一个技巧可以
- 强制包含目录的排序(即使这意味着优先考虑系统路径,尽管还指定了基于用户的位置)?
- 告诉 CMake 对
A
中的所有标头使用${A_INCLUDE_DIRS}
,对B
中的所有标头使用${B_INCLUDE_DIRS}
>?
I've got a CMake project that includes and links against two libraries, say A
and B
(actually it's more than two and one of them is boost stuff, but that doesn't really matter here). Both are located via FindSomething.cmake
scripts that (correctly) populate the standard CMake variables such that include directories are added via
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${B_INCLUDE_DIRS})
and linking is later done via
TARGET_LINK_LIBRARIES(mytarget ${A_LIBRARIES} ${B_LIBRARIES})
Now, the problem is that both libraries can either reside in a user based location or in the system directories (I'm on linux by the way, CMake 2.8.2) - or in both. Let's say A
is only in $HOME/usr/include
and $HOME/usr/lib
while B
(boost in my case) resides in both the system paths (/usr/include
and /usr/lib
) AND in the user based paths - in different versions. The find scripts can be made to find either the system or the user-based library B
, this works.
The trouble starts when I want to link against B
from the system paths.${B_INCLUDE_DIRS}
and ${B_LIBRARIES}
correctly point to the system-wide locations of the headers and libraries. But there is still ${A_INCLUDE_DIRS}
that points to a non-system include directory and ultimately also the headers for library B
are taken from this location, while the linking for B
uses the version from the system paths (via ${B_LIBRARIES}
) which leads to conflicts, i.e. linking errors.
Changing the order of the INCLUDE_DIRECTORIES
statements does not seem to change anything. I checked the origin of the symbols that cause the linking errors via nm --line-numbers
on the object files.
What can I do? Is there a trick to
- force the ordering of the include directories (even if this would mean to give precedence to a system path although there is also a user-based location specified)?
- tell CMake to use
${A_INCLUDE_DIRS}
for all headers fromA
and${B_INCLUDE_DIRS}
for all headers fromB
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
以下是 CMake 关于
include_directories()
的说法:include_directories ([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
您可以指定在您告知系统包含目录之前或之后搜索包含目录那些目录。
您还可以特定于目标:
target_include_directories(target [系统] [之前] [items1...] [ [items2...] ...])
Here's what CMake says about
include_directories()
:include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
You can specify that you want to have include directories searched before or after the system include directories at the time that you tell it about those directories.
You may also be specific to a target:
target_include_directories(target [SYSTEM] [BEFORE] [items1...] [ [items2...] ...])
如果
A
和B
是包含不同头文件和路径的不同库,那么执行您现在正在执行的操作应该没有问题。话虽这么说,如果
A
和B
是相似的库,在同一位置包含相同名称的头文件,那就有问题了。在这种情况下,include_directory()
调用的顺序很重要。我进行了一个小测试,其中有一个头文件的三个副本。第一个副本位于我的系统路径中(例如/usr/include
)。其他副本位于两个用户定义的位置(例如/tmp/include1
和/tmp/include2
)。如果我按以下顺序调用include_directory()
,则首先找到并使用/tmp/include1
中的文件:/tmp/include2< 中的文件如果我按以下顺序调用
include_directory()
,则首先找到并使用 /code>:如果我没有放置
include_directory()
语句,则系统中的标头找到并使用路径。您可能需要重新检查
FindSomething.cmake
的编写方式。find_*()
CMake 命令的搜索顺序可以在 CMake 文档,据我所知,现在有一种方法可以告诉 CMake 对来自的所有标头使用
${A_INCLUDE_DIRS}
A
和${B_INCLUDE_DIRS}
用于B
中的所有标头(如果可以在两个位置找到头文件)。这完全取决于include_directory()
调用的顺序。如果FindSomething.cmake
编写正确,如果CMAKE_MODULE_PATH
(这是 CMake 查找Find*.cmake
文件的位置)设置正确并且所有路径都良好,那么您应该可以开始了。如果没有,我将需要有关您当前的 CMake/库设置的更多信息。If
A
andB
are different libraries containing different header files and paths, there should be no problem doing what you are doing right now.That being said, if
A
andB
are similar libraries containing header files of the same name at the same location, that is problematic. In that case, the order of theinclude_directory()
call is important. I ran a little test where I had three copies of a header file. The first copy is located in my system path (say/usr/include
). The other copies are located in two user-defined locations (say/tmp/include1
and/tmp/include2
). The file in/tmp/include1
is found and used first if I put theinclude_directory()
call in the following order:The file in
/tmp/include2
is found and used first if I put theinclude_directory()
call in the following order:If I put no
include_directory()
statement, then the header in the system path is found and used.You may want to re-check how your
FindSomething.cmake
are written. The search order of thefind_*()
CMake commands can be found in the CMake documentation,As far as I can remember, there is now way of telling CMake to use
${A_INCLUDE_DIRS}
for all headers fromA
and${B_INCLUDE_DIRS}
for all headers fromB
if the header file can be found in both location. It all depends in what order theinclude_directory()
call are made. If theFindSomething.cmake
are written properly, if theCMAKE_MODULE_PATH
(this is the location where CMake will look for theFind*.cmake
files) is set properly and all the paths are good, then you should be good to go. If not, I will need more information on your current CMake/library setup.当使用第三方库时,我总是会这样做
Library A + B 头文件:
third_party/include/libA_name/ <-- put header files in
therethird_party/include/libB_name/ <-- put header files in there
在源代码中文件,你总是这样使用它
然后你仍然可以使用 -I“third_party/include”作为包含文件夹,并且源文件中不会发生排序歧义。
这也消除了自定义头文件与系统头文件的歧义,系统头文件可能会不时与第 3 方库发生冲突。
When using third party libraries, I would always do this
Library A + B header files:
third_party/include/libA_name/ <-- put header files in there
third_party/include/libB_name/ <-- put header files in there
In source files you would always use it like this
Then you can still use -I "third_party/include" as the include folder and no ambiguity in ordering will happen in source files.
This also disambiguates custom header files from system header files which could clash from time to time from 3rd party libs.
对我来说这效果很好:
For me this worked fine: