【问题标题】:Parent CMakeLists.txt overwriting child CMakeLists.txt output directory options父 CMakeLists.txt 覆盖子 CMakeLists.txt 输出目录选项
【发布时间】:2015-09-05 15:10:47
【问题描述】:

我正在尝试将项目中的库放入构建输出中的某个目录中,但父级 CMakeLists.txt 正在覆盖输出设置。 父 CMakeLists.txt 将所有库设置为放在 /lib 目录中。

但是,我的一个库需要放入 /python 库中。我在 Windows 上的设置。意思是,除了我的 python 特定库之外的所有库都放在 /lib 文件夹中,而 python 库放在 /python 文件夹中。

当我在 Linux 上构建时出现问题。所有的库,包括 python 特定的库,都放在 /lib 文件夹中。 FORCE 选项什么都不做。

如果我只为一个平台构建,我可以处理任一目录布局。但我真的很想跨平台保持相同的布局。

CMakeLists.txt 如下:

-父 CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(renderer2d)

#enable debug symbols by default
if(CMAKE_BUILD_TYPE STREQUAL "")
  set(CMAKE_BUILD_TYPE Debug)
endif()
#(you can also set on cl: -D CMAKE_BUILD_TYPE=Release)

#place outside of Debug/Release folders
SET(OUTPUT_BINDIR ${PROJECT_BINARY_DIR}/bin)
MAKE_DIRECTORY(${OUTPUT_BINDIR})

SET(OUTPUT_LIBDIR ${PROJECT_BINARY_DIR}/lib)
MAKE_DIRECTORY(${OUTPUT_LIBDIR})

SET (CMAKE_ARCHIVE_OUTPUT_DIRECTORY  ${OUTPUT_LIBDIR} CACHE PATH "build directory")
SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY  ${OUTPUT_BINDIR} CACHE PATH "build directory")
IF(WIN32)
  SET (CMAKE_LIBRARY_OUTPUT_DIRECTORY  ${OUTPUT_BINDIR} CACHE PATH "build directory")
ELSE(WIN32)
  SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR} CACHE PATH "build directory")
ENDIF(WIN32)

# For each configuration (Debug, Release, MinSizeRel... and/or anything the user chooses)
FOREACH(CONF ${CMAKE_CONFIGURATION_TYPES})
# Go uppercase (DEBUG, RELEASE...)
STRING(TOUPPER "${CONF}" CONF)
SET("CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_LIBDIR}")
SET("CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_BINDIR}")
IF(WIN32)
  SET("CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_BINDIR}")
ELSE()
  SET("CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_LIBDIR}")
ENDIF()
ENDFOREACH()

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

#set the source directory
file(GLOB SOURCES src/*.cpp)

add_subdirectory(shape)
add_subdirectory(py_shape)
add_subdirectory(scripts)

#define sources and executable
set(EXECUTABLE_NAME "renderer2d")
add_executable(${EXECUTABLE_NAME} ${SOURCES})

#find python
find_package(PythonInterp)
find_package(PythonLibs 2.7 REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})

#detect and add SFML
#this line checks a cmake file for hints on where to find cmake
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
#find any version 2.x of SFML
#see the FindSFML.cmake file for additional details and instructions
find_package(SFML 2 REQUIRED system window graphics network audio)
include_directories(${SFML_INCLUDE_DIR})

#find and include Boost python libraries
set(Boost_USE_STATIC_LIBS OFF)
find_package(Boost COMPONENTS python system filesystem REQUIRED)
include_directories(${Boost_INCLUDE_DIR})

#link all found libraries to the executable
if(WIN32)
    target_compile_definitions(${EXECUTABLE_NAME} PRIVATE $<$<BOOL:${MSVC}>:BOOST_ALL_NO_LIB>)
endif(WIN32)

target_link_libraries(${EXECUTABLE_NAME} ${PYTHON_LIBRARIES} ${SFML_LIBRARIES} ${Boost_LIBRARIES} shape)

-子 CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(py_shape CXX)

#set file variables
file(GLOB SOURCE src/*.cpp)
file(GLOB HEADERS inc/*.hpp)

#place outside of Debug/Release folders
SET(OUTPUT_BINDIR ${CMAKE_BINARY_DIR}/python)
MAKE_DIRECTORY(${OUTPUT_BINDIR})

set(OUTPUT_LIBDIR ${CMAKEK_BINARY_DIR}/python)
MAKE_DIRECTORY(${OUTPUT_LIBDIR})

SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR} CACHE PATH  "build directory")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_BINDIR} CACHE PATH  "build directory")
IF(WIN32)
  SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_BINDIR} CACHE PATH "build directory")
ELSE(WIN32)
  SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR} CACHE PATH "build directory")
ENDIF(WIN32)

#for each configuration
FOREACH(CONF ${CMAKE_CONFIGURATION_TYPES})
#Go uppercase {DEBUG, RELEASE...)
SET("CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_LIBDIR}")
SET("CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_BINDIR}")
IF(WIN32)
  SET("CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_BINDIR}")
ELSE()
  SET("CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_LIBDIR}")
ENDIF()
ENDFOREACH()

#find packages
find_package(PythonInterp)
find_package(PythonLibs 2.7 REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})

find_package(Boost COMPONENTS python REQUIRED)
include_directories(${Boost_INCLUDE_DIR})

set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
find_package(SFML 2 REQUIRED system window graphics network audio)
include_directories(${SFML_INCLUDE_DIR})

#build the library
add_library(python_shape MODULE ${SOURCE})
#enable C++11 if available
target_compile_features(python_shape PRIVATE cxx_range_for)
#link library
target_link_libraries(python_shape shape ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${SFML_LIBRARIES})
#drop "lib" from the library name
set_target_properties(python_shape PROPERTIES PREFIX "")

if(WIN32)
  #set extension to ".pyd"
  set_target_properties(python_shape PROPERTIES SUFFIX ".pyd")
endif(WIN32)

【问题讨论】:

  • 变量——比如CMAKE_ARCHIVE_OUTPUT_DIRECTORY——你正在改变的是全局变量。这些值在解析时不会应用于所有目标,但在主 CMakeLists.txt 结束时(配置步骤结束,第 1 次)将作为默认值应用于所有目标(在生成环境步骤期间,第 2 次) .并且add_subdirectory() 打开了它自己的变量范围,因此对全局变量的更改将无济于事。并且更改子 CMakeLists.txt 中的缓存值不会覆盖父 CMakeLists.txt 中设置的“正常”变量。
  • 请参阅What's the CMake syntax to set and use variables? 了解更多详情。因此,使用FORCE(在父子和子CMakeLists.txt)设置/更改缓存中的所有全局值或-根据您的描述最好-仅更改/覆盖相应的python_shape目标属性,如ARCHIVE_OUTPUT_DIRECTORY(覆盖您的在父 CMakeLists.txt 中设置的默认值仅适用于 python_shape)。
  • @Florian 我真的很想解决这个问题,而不必回来打扰你,但我无法让它发挥作用。我试过在我的孩子“CMakeLists.txt”中设置“LIBRARY_OUTPUT_DIRECTORY”,但它什么也没做。 'The python_shape' 仍然被放置在 /lib 目录中。由于这个问题,我真的在这个项目中处于停滞状态,所以如果您有任何建议,我将不胜感激。
  • 我已经对您的代码进行了一些调试。请参阅下面的答案。

标签: unix cmake cross-platform


【解决方案1】:

把我的 cmets 变成答案

我使用 MinGW 和 CMake 3.3.0 成功测试了以下内容(我稍微简化了您的示例以专注于输出目录):

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(renderer2d C CXX)

# TODO: Remove, this is just for testing
file(WRITE "src/renderer2d.cpp" "int main(void) {}") 
file(WRITE "py_shape/src/py_shape.cpp" "") 

#enable debug symbols by default
if(CMAKE_BUILD_TYPE STREQUAL "")
  set(CMAKE_BUILD_TYPE Debug)
endif()
#(you can also set on cl: -D CMAKE_BUILD_TYPE=Release)

#place outside of Debug/Release folders
#see http://www.cmake.org/Wiki/CMake_Useful_Variables
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/bin")
if(WIN32)
  set(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}")
else()
  set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib")
endif()

#see https://stackoverflow.com/questions/10851247/how-to-activate-c-11-in-cmake
if (CMAKE_VERSION VERSION_LESS "3.1")
  if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set(CMAKE_CXX_FLAGS "--std=gnu++11 ${CMAKE_CXX_FLAGS}")
  endif()
else()
  set(CMAKE_CXX_STANDARD 11)
endif()

#set the source directory
file(GLOB SOURCES src/*.cpp)

add_subdirectory(py_shape)

#define sources and executable
add_executable(${PROJECT_NAME} ${SOURCES})

add_dependencies(${PROJECT_NAME} python_shape)

py_shape/CMakeLists.txt

#set file variables
file(GLOB SOURCE src/*.cpp)
file(GLOB HEADERS inc/*.hpp)

#build the library
add_library(python_shape MODULE ${SOURCE})

set_target_properties(python_shape PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/python")

#drop "lib" from the library name
set_target_properties(python_shape PROPERTIES PREFIX "")

if(WIN32)
  #set extension to ".pyd"
  set_target_properties(python_shape PROPERTIES SUFFIX ".pyd")
endif()

现在python_shape.pydpython 子目录中创建。

我已更改/删除的内容:

  • 在子 CMakeLists.txt 中设置 ..._OUTPUT_DIRECTORY 全局变量不是必需的和/或不起作用
  • 添加了LIBRARY_OUTPUT_DIRECTORY 以覆盖python_shape MODULE 库目标的输出目录(另请参见Custom Directory for CMake Library Output
  • 删除了“按配置”设置,因为我认为这是一个功能,让 Visual Studio 等多配置环境将不同的配置二进制文件放入同名的子文件夹中。
  • -std=c++11 周围添加了一些if 语句。它也只需在主CMakeLists.txt 中设置一次
  • 您无需“手动”创建输出目录,它们由 make 环境自动创建

有关您的第一种方法不起作用的原因,请参阅上面的我的 cmets。

而且我不建议使用file(GLOB ...) 来收集源文件(参见例如Why is cmake file GLOB evil?CMake/Ninja attempting to compile deleted `.cpp` file)。

替代品

CMake 等所有语言/框架一样,做事的方法不止一种。

例如您还可以使用POST_BUILD 步骤将您的二进制文件复制到一个公共输出目录:

【讨论】:

    猜你喜欢
    • 2011-04-15
    • 1970-01-01
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    相关资源
    最近更新 更多