Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
CMake配置从根目录或子目录构建项目_Cmake_Dependencies_Subdirectory - Fatal编程技术网

CMake配置从根目录或子目录构建项目

CMake配置从根目录或子目录构建项目,cmake,dependencies,subdirectory,Cmake,Dependencies,Subdirectory,我最近开始使用CMake(2.8.12.2,CentOS 6.8中包含的一个),我认为它足够强大,可以帮助我完成我想要的,但我还没有弄清楚如何:-),因此我呼吁您的智慧帮助我找到缺失的一点 我的项目布局如下: BaseDir | +-->bin (generated by the process) | | | +-->Debug | +-->Release | +-->lib (generated by the process) | | |

我最近开始使用CMake(2.8.12.2,CentOS 6.8中包含的一个),我认为它足够强大,可以帮助我完成我想要的,但我还没有弄清楚如何:-),因此我呼吁您的智慧帮助我找到缺失的一点

我的项目布局如下:

BaseDir
|
+-->bin (generated by the process)
|    |
|    +-->Debug
|    +-->Release
|
+-->lib (generated by the process)
|    |
|    +-->Debug
|    +-->Release
|    
+-->CMakeLists.txt
|
+-->Library_A
|    |
|    +-->CMakeLists.txt
|    +-->include
|    +-->src
|    |    |
|    |    +-->CMakeLists.txt
|    |
|    +-->test # Small binary to test solely the library functions 
|        |
|        +-->CMakeLists.txt
|
+-->Library_B (depends on Library_A)
|    |
|    +-->CMakeLists.txt
|    +-->include
|    +-->src
|    |    |
|    |    +-->CMakeLists.txt
|    |
|    +-->test # Small binary to test solely the library functions 
|        |
|        +-->CMakeLists.txt
|
+-->Application_1 (depends on Library_B, hence transitivitely depends on Library_A)
|    |
|    +-->CMakeLists.txt
|    +-->include
|    +-->src
|        |
|        +-->CMakeLists.txt
|
+-->Application_2 (depends on Library_A)
    |
    +-->CMakeLists.txt
    +-->include
    +-->src
        |
        +-->CMakeLists.txt
当我把自己放在BaseDir下运行“cmake”时,它就像一个符咒。应用程序1、应用程序2、库A和库B都以正确的顺序构建、链接等

然而,我的想法是能够在任何子目录(Application、Library)下进行构建,在这种情况下,只构建与之相关的代码(即它本身、它的测试和它的依赖项)。例如,当站在库_A中时,仅生成该文件夹,而从库_B中也生成库_A,以及在应用程序_1或应用程序_2下发生的等效情况。另外,在触发cmake进程的位置上,构建结果(lib或bin)必须始终放在BaseDir/{lib|bin}/{Debug/Release/etc}下,而不能放在库或应用程序子目录下。例如,它意味着库_B(依赖于库_A)或应用程序_1(依赖于库_A和B)的链接必须查看BaseDir/lib/{Debug/Release}

我的目标是在BaseDir下有许多应用程序,所以如果不是真的需要,我希望避免每次都要构建它们,只构建我想要的单个应用程序

我也研究过,但这与我在这里试图实现的情况并不完全相同

我尝试过以下方法:

BaseDir/CMakeLists.txt
|
|    cmake_minimum_required (VERSION 2.8)
|    project (BASE_DIR)
|
|    add_subdirectory (Library_A)     # No local dependencies
|    add_subdirectory (Library_B)     # Depends on A
|    add_subdirectory (Application_1) # Depends on A and B
|    add_subdirectory (Application_2) # Depends on A
|
|    # I want all binary outputs (executables and libraries) placed under BaseDir/{lib|bin}/{Debug|Release}
|    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}") # For the executables
|    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/${CMAKE_BUILD_TYPE}") # For the static libraries
|    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/${CMAKE_BUILD_TYPE}") # For the dynamic libraries
|
+-->BaseDir/Library_A/CMakeLists.txt (again, no dependencies)
|    |
|    |    cmake_minimum_required (VERSION 2.8)
|    |    project (LIB_A)
|    |    
|    |    # In case CMake is run from within BaseDir/Library_A and not from BaseDir, I still want the outputs being placed under BaseDir/{lib|bin}/{Debug|Release}
|    |    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}") # For the test executables
|    |    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib/${CMAKE_BUILD_TYPE}") # For the static libraries
|    |    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib/${CMAKE_BUILD_TYPE}") # For the dynamic libraries
|    |
|    |    include_directories(include)
|    |    add_subdirectory (src)
|    |    add_subdirectory (test)
|    |    set(${PROJECT_NAME}_INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}/include CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
|    |
|    +-->BaseDir/Library_A/src/CMakeLists.txt
|    |
|    |        cmake_minimum_required (VERSION 2.8)
|    |
|    |        # add all files in the current directory
|    |        file(GLOB LIB_A_SRCS "*.h" "*.cpp")
|    |
|    |        # Create a library called libA.a
|    |        add_library(A ${LIB_A_SRCS})
|    |
|    +-->BaseDir/Library_A/test/CMakeLists.txt
|    
|            cmake_minimum_required (VERSION 2.8)
|    
|            # add all files in the current directory
|            file(GLOB TEST_A_SRCS "*.h" "*.cpp")
|    
|            # Create an executable file from sources
|            add_executable(TEST_A ${TEST_A_SRCS})
|    
|            # Link this executable to the library it's testing
|            target_link_libraries(TEST_A A)
|    
+-->BaseDir/Library_B/CMakeLists.txt (dependency on A)
|    |    
|    |    cmake_minimum_required (VERSION 2.8)
|    |    project (LIB_B)
|    |    
|    |    # In case CMake is run from within BaseDir/Library_B and not from BaseDir, I still want the outputs being placed under BaseDir/{lib|bin}/{Debug|Release}
|    |    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}") # For the test executables
|    |    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib/${CMAKE_BUILD_TYPE}") # For the static libraries
|    |    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib/${CMAKE_BUILD_TYPE}") # For the dynamic libraries
|    |
|    |    include_directories(include)
|    |    add_subdirectory (src)
|    |    add_subdirectory (test)
|    |    set(${PROJECT_NAME}_INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}/include CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
|    |
|    +-->BaseDir/Library_B/src/CMakeLists.txt
|    |
|    |        cmake_minimum_required (VERSION 2.8)
|    |
|    |        # add all files in the current directory
|    |        file(GLOB LIB_B_SRCS "*.h" "*.c")
|    |
|    |        # Create a library called libB.a
|    |        add_library(B ${LIB_B_SRCS})
|    |        
|    |        # Add a dependency to Library_A
|    |        find_library(LIBRARY_A A PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../../Library_A)
|    |        include_directories("$LIB_A_INCLUDE_DIRECTORIES")
|    |        target_link_libraries(B ${LIBRARY_A}) 
|    |
|    +-->BaseDir/Library_B/test/CMakeLists.txt
|
|            cmake_minimum_required (VERSION 2.8)
|
|            # add all files in the current directory
|            file(GLOB TEST_B_SRCS "*.h" "*.cpp")
|
|            # Create an executable file from sources, for both versions of the library
|            add_executable(TEST_B ${TEST_B_SRCS})
|            
|            # Link this executable to the library it's testing
|            target_link_libraries(TEST_B B)
|
+-->BaseDir/Application_1/CMakeLists.txt
|    |
|    |    cmake_minimum_required (VERSION 2.8)
|    |    project (APP_1)
|    |    
|    |    # In case CMake is run from within BaseDir/Application_1 and not from BaseDir, I still want the outputs being placed under BaseDir/{lib|bin}/{Debug|Release}
|    |    # In this case, only executables are generated.
|    |    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}")
|    |
|    |    include_directories(include)
|    |    add_subdirectory (src)
|    |
|    +-->BaseDir/Application_1/src/CMakeLists.txt
|
|            cmake_minimum_required (VERSION 2.8)
|
|            # add all files in the current directory
|            file(GLOB APP_1_SRCS "*.cpp")
|
|            # Create an executable file from sources
|            add_executable(EXE_1 ${APP_1_SRCS})
|            
|            # This should automatically bring Library_A
|            find_library(LIBRARY_B B PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../../Library_B)
|            include_directories(${LIB_B_INCLUDE_DIRECTORIES})
|            target_link_libraries(EXE_1 ${LIBRARY_B})
|
+-->BaseDir/Application_2/CMakeLists/CMakeLists.txt
    |
    |    cmake_minimum_required (VERSION 2.8)
    |    project (APP_2)
    |    
    |    # In case CMake is run from within BaseDir/Application_2 and not from BaseDir, I still want the outputs being placed under BaseDir/{lib|bin}/{Debug|Release}
    |    # In this case, only executables are generated.
    |    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}")
    |
    |    include_directories(include)
    |    add_subdirectory (src)
    |
    +-->BaseDir/Application_2/src/CMakeLists.txt

            cmake_minimum_required (VERSION 2.8)

            # add all files in the current directory
            file(GLOB APP_2_SRCS "*.cpp")

            # Create an executable file from sources
            add_executable(EXE_2 ${APP_2_SRCS})

            # Link this executable to the library it needs
            find_library(LIBRARY_A A PATHS ${CMAKE_CURRENT_SOURCE_DIR}../../Library_A)
            include_directories(${LIB_A_INCLUDE_DIRECTORIES})
            target_link_libraries(EXE_2 ${LIBRARY_A})
但是没有运气,因为当我从子目录(例如,BaseDir/Application_1)运行时,我只得到:

CMake错误:此项目中使用了以下变量,但它们被设置为NOTFOUND。 请设置或确保在CMake文件中正确设置和测试: 图书馆

我想,“find_library()”调用不足以满足我的需要,这基本上是加载libraries项目中包含的所有设置,不仅包括库本身,还包括该库添加的include目录。find_library()的具体用法是什么,将它指向创建库的项目的位置,或实际生成的库(“.a”或“.so”)

所以,我的主要疑问是:这种布局可行吗?如果是,我错过了什么?我是否应该使用类似于查找包()查找路径()的方法?如何从另一个“相同级别”CMakeLists.txt触发对CMakeLists.txt配置文件的解析


PS:我真的需要考虑在任何时候使用<强>“AddiSuffiCeCes()”<强>吗?如果没有,该命令的意义何在?

首先是一条一般性建议:在CMake中,您将始终希望尝试严格地将构建目录与源目录分开。尤其是,在构建过程中,不应将文件写回源目录。编写脚本,以便它们也能与装载在只读文件系统上的源目录一起工作。虽然一开始这看起来像是一个任意的限制,但从长远来看,它实际上会帮助您避免许多麻烦

至于您的实际问题:
find_library
是解决依赖性问题的非常低级的工具。这里的想法基本上是,您在系统的某个地方安装了第三方库的二进制文件(该库本身对CMake一无所知),您知道只需检查文件系统的内容就可以找到它们。这里的情况并非如此,因为您将依赖项构建为同一CMake配置运行的一部分

相反,您要做的是直接依赖于依赖项的目标。因此,与其这样做,不如:

find_library(LIBRARY_A A)
target_link_libraries(B ${LIBRARY_A}) 
你会直接写信吗

target_link_libraries(B A)
当然,只有当
A
是当时已知的目标时,这才有效,这是您应该关注的问题

只要您在同一个CMake运行中一起构建库,这是非常简单的:如果目标是由父目录或同级目录添加的,您应该能够立即使用它。在您的情况下,使事情复杂化的是,您还希望能够独立地构建不同的库。这意味着您需要一种机制,将目标导入到您的构建中,使其看起来像是作为同一个CMake运行的一部分再次生成的目标


您可以通过添加并设置其接口属性手动执行此操作,也可以使用CMake以自动方式执行此操作。请注意,这两项都不是小事,因此,您可能希望从一个简单的案例开始,在一次CMake运行中完成所有操作,然后在您更熟悉使用CMake之后添加对分离构建的支持。

首先,一条一般性建议:在CMake中,您将始终希望尝试严格地将构建目录与源目录分离。尤其是,在构建过程中,不应将文件写回源目录。编写脚本,以便它们也能与装载在只读文件系统上的源目录一起工作。虽然一开始这看起来像是一个任意的限制,但从长远来看,它实际上会帮助您避免许多麻烦

至于您的实际问题:
find_library
是解决依赖性问题的非常低级的工具。这里的想法基本上是,您在系统的某个地方安装了第三方库的二进制文件(该库本身对CMake一无所知),您知道只需检查文件系统的内容就可以找到它们。这里的情况并非如此,因为您将依赖项构建为同一CMake配置运行的一部分

你想做的是直接