CMake 在导入静态库时的奇怪行为

huangapple go评论61阅读模式
英文:

Strange behavior from CMake when importing a STATIC library

问题

以下是要翻译的内容:

主要问题:
我在使用CMake导入yaml-cpp静态库时遇到了一个奇怪的问题(错误?)。

main.cpp

#include "yaml-cpp/yaml.h"

CMakeLists.txt(可行)

add_library(yaml-cpp ${PROJECT_BINARY_DIR}/path/to/libyaml-cpp.a)
target_link_libraries(main yaml-cpp)

CMakeLists.txt(不可行)

add_library(yaml-cpp STATIC IMPORTED)                                 
set_target_properties(yaml-cpp PROPERTIES IMPORTED_LOCATION ${PROJECT_BINARY_DIR}/path/to/libyaml-cpp.a)  
target_link_libraries(main yaml-cpp)  

当我使用第二个CMakeLists.txt时,main.cpp 无法找到 yaml-cpp/yaml.h。但当我使用第一个CMakeLists.txt时,虽然能够找到,但每次配置项目时都会收到 "ar: no archive members specified" 的消息,这很烦人。我想以第二种方式导入它,以摆脱这个消息。

英文:

I'm experiencing a strange (bug?) when importing the yaml-cpp static library with CMake.

main.cpp

#include "yaml-cpp/yaml.h"

CMakeLists.txt (working)

add_library(yaml-cpp ${PROJECT_BINARY_DIR}/path/to/libyaml-cpp.a)
target_link_libraries(main yaml-cpp)

CMakeLists.txt (not working)

add_library(yaml-cpp STATIC IMPORTED)                                
set_target_properties(yaml-cpp PROPERTIES IMPORTED_LOCATION ${PROJECT_BINARY_DIR}/path/to/libyaml-cpp.a)  
target_link_libraries(main yaml-cpp)  

When I use the second CMakeLists.txt, my main.cpp cannot find yaml-cpp/yaml.h. When I use the first CMakeLists.txt, it can, however, I get the "ar: no archive members specified" message every time I configure the project, which is annoying. Would like to import it the second way to get rid of that message.

答案1

得分: 0

你的第一个片段没有意义。

第二个片段缺少INTERFACE_INCLUDE_DIRECTORIES属性。

add_library(yaml-cpp STATIC IMPORTED)
set_target_properties(yaml-cpp PROPERTIES
    INTERFACE_INCLUDE_DIRECTORIES "<path/to/includedir>"
    IMPORTED_LOCATION "<path/to/static_lib>"
)

但正如答案中提到的,为什么不使用find_package()呢,因为yaml-cpp提供了一个CMake配置文件?

英文:

Your first snippet doesn't make sense.

The second one is missing INTERFACE_INCLUDE_DIRECTORIES property.

add_library(yaml-cpp STATIC IMPORTED)
set_target_properties(yaml-cpp PROPERTIES
    INTERFACE_INCLUDE_DIRECTORIES &quot;&lt;path/to/includedir&gt;&quot;
    IMPORTED_LOCATION &quot;&lt;path/to/static_lib&gt;&quot;
)

But as mentioned in an answer, why don't you use find_package() since yaml-cpp provides a CMake config file?

答案2

得分: 0

I'm not aware of "add_library(yaml-cpp ${PROJECT_BINARY_DIR}/path/to/libyaml-cpp.a)" being a valid usage of add_library. See the docs. You can use absolute paths to library binaries in target_link_libraries (but I'd consider that an antipattern here and I'll explain why).

I'm pretty sure the problem is that you haven't done target_include_directories(yaml-cpp INTERFACE <path to include directory for yaml-cpp>) (or equivalently, set the INTERFACE_INCLUDE_DIRECTORIES target property).

But I'd suggest you just use find_package. From what I see in yaml-cpp's CMakeLists.txt, it does create a find-config script. Build and install yaml-cpp, and then call find_package(yaml-cpp ...), which will make available the yaml-cpp::yaml-cpp target with correct configuration for include directory options and import location.

英文:

I'm not aware of "add_library(yaml-cpp ${PROJECT_BINARY_DIR}/path/to/libyaml-cpp.a)" being a valid usage of add_library. see the docs. You can use absolute paths to library binaries in target_link_libraries (but I'd consider that an antipattern here and I'll explain why).

I'm pretty sure the problem is that you haven't done target_include_directories(yaml-cpp INTERFACE &lt;path to include directory for yaml-cpp&gt;) (or equivalently, set the INTERFACE_INCLUDE_DIRECTORIES target property).

But I'd suggest you just use find_package. From what I see in yaml-cpp's CMakeLists.txt, it does create a find-config script. Build and install yaml-cpp, and then call find_package(yaml-cpp ...), which will make available the yaml-cpp::yaml-cpp target with correct configuration for include directory options and import location.

答案3

得分: -1

对于你们两位的回答,我很感激。事实证明我应该在我的问题中提供更多信息。问题基本上是因为我试图创建一个便携式安装,将每个依赖项的整个源代码放在项目文件夹结构中,这是我以前从未尝试过的。对我来说,似乎逻辑上库文件(.a,.dylib等)应该包含所有的头文件,但显然并非如此。我将提供一些我是如何解决这个问题的细节。

  1. 在其余项目之前构建库是正确的选择,但我忘记了安装它们。cmake -> make -> make install

BuildLibraries.txt(cmake 文件)

    set(yaml-cpp_cmakelists &quot;${CMAKE_SOURCE_DIR}/external/yaml-cpp-master&quot;)
    set(yaml-cpp_build_location &quot;${CMAKE_BINARY_DIR}/external/yaml-cpp-master&quot;)        
    file(MAKE_DIRECTORY ${yaml-cpp_build_location})  

    execute_process(                                                                     
        COMMAND ${CMAKE_COMMAND} -S ${yaml-cpp_cmakelists} -B ${yaml-cpp_build_location} -D CMAKE_INSTALL_PREFIX=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} -D BUILD_SHARED_LIBS=OFF
        WORKING_DIRECTORY ${yaml-cpp_build_location}
        RESULT_VARIABLE result
    )
    if(NOT result EQUAL 0)
        message(FATAL_ERROR &quot;Failed to configure yaml-cpp&quot;)
    endif()

    execute_process(                                                                     
        COMMAND make -C ${yaml-cpp_build_location} -j4
        WORKING_DIRECTORY ${yaml-cpp_build_location}
        RESULT_VARIABLE result
    )
    if(NOT result EQUAL 0)
        message(FATAL_ERROR &quot;Failed to generate yaml-cpp&quot;)
    endif()

    execute_process(                                                                     
        COMMAND make install -C ${yaml-cpp_build_location} -j4
        WORKING_DIRECTORY ${yaml-cpp_build_location}
        RESULT_VARIABLE result
    )
    if(NOT result EQUAL 0)
        message(FATAL_ERROR &quot;Failed to install yaml-cpp&quot;)
    endif()
  1. 在项目根目录的 CMakeLists.txt 中:
    • 确保 find_package() 知道在哪里查找你使用 set(CMAKE_PREFIX_PATH ...) 安装的库
    • 接着使用 find_package()。就像这些用户建议的那样,这样做会更容易。

CMakeLists.txt(在根项目目录中)

   cmake_minimum_required(VERSION 3.26.0)                           
   set(CMAKE_CXX_STANDARD 17)
   set(CMAKE_CXX_STANDARD_REQUIRED ON)

   set(REBUILD_LIBS ON)                                             # 选择在生成阶段重新构建库

   set(PROJECT_BINARY_DIR &quot;${CMAKE_SOURCE_DIR}/build&quot;)              # 根构建目录
   set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY &quot;${PROJECT_BINARY_DIR}&quot;)      # 静态库
   set(CMAKE_INSTALL_LIBDIR ${PROJECT_BINARY_DIR}/lib)
   set(CMAKE_INSTALL_BINDIR ${PROJECT_BINARY_DIR})
   set(CMAKE_LIBRARY_OUTPUT_DIRECTORY &quot;${PROJECT_BINARY_DIR}&quot;)      # 共享库
   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY &quot;${PROJECT_BINARY_DIR}&quot;)      # 可执行文件
   set(CMAKE_PREFIX_PATH                                            # 定义 find_package() 的搜索路径
       &quot;${PROJECT_BINARY_DIR}/lib/cmake&quot;
   )  

   if(REBUILD_LIBS)
       include(${CMAKE_SOURCE_DIR}/CMakeFiles/BuildLibraries.txt)   # 使用 BuildLibraries.txt CMakeLists.txt 文件构建外部库
   endif()


   project(myProject)     
   add_executable(main main.cpp) 

   find_package (yaml-cpp)

   target_link_libraries(main yaml-cpp)
英文:

For both of you who answered, I appreciate it. Turns out I should have provided more information in my question. The issue was arising basically from the fact that I am attempting to create a portable installation, with the entire source of each of the dependencies within the project folder-structure, which is something that I haven't attempted before. It seemed logical to me that the library files (.a, .dylib, etc..) would contain all of the headers within them, but apparently that is not the case. I will provide a few details on how I was able to fix the issue.

  1. Building the libraries before the rest of the project was the right move, but I forgot to install them. cmake -> make -> make install

BuildLibraries.txt (cmake file)

    set(yaml-cpp_cmakelists &quot;${CMAKE_SOURCE_DIR}/external/yaml-cpp-master&quot;)
    set(yaml-cpp_build_location &quot;${CMAKE_BINARY_DIR}/external/yaml-cpp-master&quot;)        
    file(MAKE_DIRECTORY ${yaml-cpp_build_location})  

    execute_process(                                                                     
        COMMAND ${CMAKE_COMMAND} -S ${yaml-cpp_cmakelists} -B ${yaml-cpp_build_location} -D CMAKE_INSTALL_PREFIX=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} -D BUILD_SHARED_LIBS=OFF
        WORKING_DIRECTORY ${yaml-cpp_build_location}
        RESULT_VARIABLE result
    )
    if(NOT result EQUAL 0)
        message(FATAL_ERROR &quot;Failed to configure yaml-cpp&quot;)
    endif()

    execute_process(                                                                     
        COMMAND make -C ${yaml-cpp_build_location} -j4
        WORKING_DIRECTORY ${yaml-cpp_build_location}
        RESULT_VARIABLE result
    )
    if(NOT result EQUAL 0)
        message(FATAL_ERROR &quot;Failed to generate yaml-cpp&quot;)
    endif()

    execute_process(                                                                     
        COMMAND make install -C ${yaml-cpp_build_location} -j4
        WORKING_DIRECTORY ${yaml-cpp_build_location}
        RESULT_VARIABLE result
    )
    if(NOT result EQUAL 0)
        message(FATAL_ERROR &quot;Failed to install yaml-cpp&quot;)
    endif()
  1. Inside project-root directory CMakeLists.txt:
    • ensure that find_package() knows where to look for the libraries that you installed using set(CMAKE_PREFIX_PATH ...)
    • go ahead and use find_package(). It is, as these users suggested, much easier.

CMakeLists.txt (in root project directory)

       cmake_minimum_required(VERSION 3.26.0)                           
       set(CMAKE_CXX_STANDARD 17)
       set(CMAKE_CXX_STANDARD_REQUIRED ON)

       set(REBUILD_LIBS ON)                                             # choose wether to rebuild libraries during the generate phase

       set(PROJECT_BINARY_DIR &quot;${CMAKE_SOURCE_DIR}/build&quot;)              # root build directory
       set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY &quot;${PROJECT_BINARY_DIR}&quot;)      # static libraries
       set(CMAKE_INSTALL_LIBDIR ${PROJECT_BINARY_DIR}/lib)
       set(CMAKE_INSTALL_BINDIR ${PROJECT_BINARY_DIR})
       set(CMAKE_LIBRARY_OUTPUT_DIRECTORY &quot;${PROJECT_BINARY_DIR}&quot;)      # shared libraries
       set(CMAKE_RUNTIME_OUTPUT_DIRECTORY &quot;${PROJECT_BINARY_DIR}&quot;)      # executables
       set(CMAKE_PREFIX_PATH                                            # define search-paths for find_package()
           &quot;${PROJECT_BINARY_DIR}/lib/cmake&quot;
       )  

       if(REBUILD_LIBS)
           include(${CMAKE_SOURCE_DIR}/CMakeFiles/BuildLibraries.txt)   # Build external libraries using the BuildLibraries.txt CMakeLists.txt file
       endif()


       project(myProject)     
       add_executable(main main.cpp) 

       find_package (yaml-cpp)

       target_link_libraries(main yaml-cpp)  

huangapple
  • 本文由 发表于 2023年6月2日 01:45:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76384430.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定