英文:
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 "<path/to/includedir>"
    IMPORTED_LOCATION "<path/to/static_lib>"
)
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 <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.
答案3
得分: -1
对于你们两位的回答,我很感激。事实证明我应该在我的问题中提供更多信息。问题基本上是因为我试图创建一个便携式安装,将每个依赖项的整个源代码放在项目文件夹结构中,这是我以前从未尝试过的。对我来说,似乎逻辑上库文件(.a,.dylib等)应该包含所有的头文件,但显然并非如此。我将提供一些我是如何解决这个问题的细节。
- 在其余项目之前构建库是正确的选择,但我忘记了安装它们。cmake -> make -> make install
 
BuildLibraries.txt(cmake 文件)
    set(yaml-cpp_cmakelists "${CMAKE_SOURCE_DIR}/external/yaml-cpp-master")
    set(yaml-cpp_build_location "${CMAKE_BINARY_DIR}/external/yaml-cpp-master")        
    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 "Failed to configure yaml-cpp")
    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 "Failed to generate yaml-cpp")
    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 "Failed to install yaml-cpp")
    endif()
- 在项目根目录的 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 "${CMAKE_SOURCE_DIR}/build")              # 根构建目录
   set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")      # 静态库
   set(CMAKE_INSTALL_LIBDIR ${PROJECT_BINARY_DIR}/lib)
   set(CMAKE_INSTALL_BINDIR ${PROJECT_BINARY_DIR})
   set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")      # 共享库
   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")      # 可执行文件
   set(CMAKE_PREFIX_PATH                                            # 定义 find_package() 的搜索路径
       "${PROJECT_BINARY_DIR}/lib/cmake"
   )  
   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.
- 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 "${CMAKE_SOURCE_DIR}/external/yaml-cpp-master")
    set(yaml-cpp_build_location "${CMAKE_BINARY_DIR}/external/yaml-cpp-master")        
    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 "Failed to configure yaml-cpp")
    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 "Failed to generate yaml-cpp")
    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 "Failed to install yaml-cpp")
    endif()
- 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 "${CMAKE_SOURCE_DIR}/build")              # root build directory
       set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")      # static libraries
       set(CMAKE_INSTALL_LIBDIR ${PROJECT_BINARY_DIR}/lib)
       set(CMAKE_INSTALL_BINDIR ${PROJECT_BINARY_DIR})
       set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")      # shared libraries
       set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")      # executables
       set(CMAKE_PREFIX_PATH                                            # define search-paths for find_package()
           "${PROJECT_BINARY_DIR}/lib/cmake"
       )  
       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)  
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论