Cmake能生成一个同时支持调试和发布的makefile吗

xqnpmsa8  于 2023-10-16  发布在  其他
关注(0)|答案(3)|浏览(88)

看起来我们需要为每个构建类型(调试/发布)创建单独的文件夹,在每个构建类型上运行cmake,并为调试/发布配置生成单独的makefile。有没有可能使用cmake创建一个单独的makefile,它同时支持调试/发布配置,当我们实际运行“make”时,它将为中间产品和最终产品创建单独的文件夹(如dll,exe)。

vq8itlhq

vq8itlhq1#

据我所知,这不能通过使用一组构建脚本来实现。然而,你可以做的是在你的工作区域有两个子目录:

build/
build/debug
build/release

然后执行:

$ cd build
$
$ cd build/debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ../..
$ make
$
$ cd ../release
$ cmake -DCMAKE_BUILD_TYPE=Release ../..
$ make

如有必要,您可以在build目录中添加另一个构建脚本,如下所示:

#!/bin/sh
cd debug   && make && cd ..
cd release && make && cd ..
xwmevbvl

xwmevbvl2#

这可以使用ADD_CUSTOM_TARGET命令来实现。例如,如果要在makefile中添加调试和发布目标,请将以下内容添加到CMakeLists.txt文件中:

ADD_CUSTOM_TARGET(debug
  COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR}
  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
  COMMENT "Creating the executable in the debug mode.")

ADD_CUSTOM_TARGET(release
  COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR}
  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
  COMMENT "Creating the executable in the release mode.")

然后,在使用cmake进行配置之后,可以在同一目录中运行make debug来设置调试目标,并运行make release来设置发布目标。

r6vfmomb

r6vfmomb3#

感谢@a.sam的回答,我现在可以提供一个独立的工作示例;你可以以后再谢我:)
本质上,这里我发明了一个CMAKE_BUILD_TYPE,它不存在于cmake中(cmake不知道它),这里称为SingleBuildDir,并使用它来区分创建顶级Makefile或调试/发布Makefile。
只需保存下面的文件作为CMakeLists.txt某处:

# instead of calling the following in build subdir, as we used to:
# cmake.exe  ../ -DCMAKE_BUILD_TYPE=Debug -G "MSYS Makefiles"
# now we want to try something like:
# cmake.exe  ../ -DCMAKE_BUILD_TYPE=SingleBuildDir -G "MSYS Makefiles"
# ... and then have `make debug` build in build/Debug, and `make release` build in build/Release
# see https://stackoverflow.com/questions/10083427/can-cmake-generate-a-single-makefile-that-supports-both-debug-and-release

cmake_minimum_required(VERSION 3.13)

# https://stackoverflow.com/questions/18968979/how-to-make-colorized-message-with-cmake
#if(NOT WIN32) # well, get rid of this, as it detects MINGW bash as WIN32 too
  string(ASCII 27 Esc)
  set(ColourReset "${Esc}[m")
  set(ColourBold  "${Esc}[1m")
  set(Red         "${Esc}[31m")
  set(Green       "${Esc}[32m")
  set(Yellow      "${Esc}[33m")
  set(Blue        "${Esc}[34m")
  set(Magenta     "${Esc}[35m")
  set(Cyan        "${Esc}[36m")
  set(White       "${Esc}[37m")
  set(BoldRed     "${Esc}[1;31m")
  set(BoldGreen   "${Esc}[1;32m")
  set(BoldYellow  "${Esc}[1;33m")
  set(BoldBlue    "${Esc}[1;34m")
  set(BoldMagenta "${Esc}[1;35m")
  set(BoldCyan    "${Esc}[1;36m")
  set(BoldWhite   "${Esc}[1;37m")
#endif()

if (NOT(EXISTS "${CMAKE_SOURCE_DIR}/main.c" AND NOT IS_DIRECTORY "${CMAKE_SOURCE_DIR}/main.c"))
  message("${Cyan}Creating ${CMAKE_SOURCE_DIR}/main.c${ColourReset}")
  # https://stackoverflow.com/questions/7637539/how-to-split-strings-across-multiple-lines-in-cmake
  # https://stackoverflow.com/questions/69574555/cmake-filegenerate-output-output-file-how-to-write-content-on-multiple
  # https://stackoverflow.com/questions/67674998/cmakelists-create-string-with-new-lines
  # https://stackoverflow.com/questions/26193171/cmake-how-to-create-a-file-with-make-command # example for file(write
  FILE(WRITE ${CMAKE_SOURCE_DIR}/main.c
    "#include <stdio.h>\n"
    "\n"
    "int main() {\n"
    "  printf(\"Hello from test_cmake_singlebuilddir main.exe!\\n\");\n"
    "  return 0;\n"
    "}\n"
  )
endif() # NOT(EXISTS "${CMAKE_SOURCE_DIR}/main.c"

# NOTE: apparently, project command MUST be first;
# else the `make debug` might fail with "Error: could not find CMAKE_PROJECT_NAME in Cache"
# (via [Error could not find CMAKE_PROJECT_NAME in Cache · Issue #90 · facebookresearch/habitat-sim · GitHub](https://github.com/facebookresearch/habitat-sim/issues/90))
project(test_singlebuilddir C)

message("${Cyan}Current CMAKE_BUILD_TYPE mode: ${CMAKE_BUILD_TYPE}${ColourReset}")

if(CMAKE_BUILD_TYPE STREQUAL "SingleBuildDir")
  message("${Yellow}Create subdirectories in build (${CMAKE_BINARY_DIR}): ./Debug, ./Release${ColourReset}")
  # https://stackoverflow.com/questions/3702115/creating-a-directory-in-cmake
  # "CMAKE_BINARY_DIR is defined and cached based on the directory that you run the cmake command" SO:10083427
  file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Debug)
  file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Release)

  message("${Yellow}Creating top-level makefile${ColourReset}") # SO:10083427

  message("${Yellow}Initialize Debug directory${ColourReset}")
  execute_process(
    COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR} -DCMAKE_BUILD_TYPE=Debug -G "${CMAKE_GENERATOR}"
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debug
  )
  message("${Yellow}Add debug build target${ColourReset}")
  ADD_CUSTOM_TARGET(debug
    COMMAND ${CMAKE_COMMAND} --build . --target all
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debug
    COMMENT "Creating the executable in the debug mode."
  )

  message("${Yellow}Initialize Release directory${ColourReset}")
  execute_process(
    COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR} -DCMAKE_BUILD_TYPE=Release -G "${CMAKE_GENERATOR}"
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Release
  )
  message("${Yellow}Add release build target${ColourReset}")
  ADD_CUSTOM_TARGET(release
    COMMAND ${CMAKE_COMMAND} --build . --target all
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Release
    COMMENT "Creating the executable in the release mode."
  )

  # if we ended up here, exit early; no real cmake command for that:
  # https://stackoverflow.com/questions/57192628/can-i-stop-cmake-processing-without-an-error
  # ... but try return?:
  return() # seems to work!
endif() # CMAKE_BUILD_TYPE STREQUAL "SingleBuildDir"

message("${Cyan}Proceed with rest of CMakeLists.txt - actual project setup ...${ColourReset}")

#project(test_singlebuilddir C) # if here, "Error: could not find CMAKE_PROJECT_NAME in Cache"
set(CMAKE_C_STANDARD 11)
message("${Cyan}PROJECT_NAME is '${PROJECT_NAME}'${ColourReset}")

set(${PROJECT_NAME}_sources
    main.c
)

add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_sources})

命令行输出如下:注意我必须传播-g“MSYS 2 Makefiles”,因为我在Windows MSYS 2 bash shell上:

$ # in the directory where CMakeLists.txt is:
$ mkdir build
$ cd build

$ # check state of this and parent folder
$ ls -la ..
total 20K
drwxr-xr-x 1 user None    0 Oct  6 19:14 ./
drwxr-xr-x 1 user None    0 Oct  6 17:40 ../
drwxr-xr-x 1 user None    0 Oct  6 19:14 build/
-rw-r--r-- 1 user None 4.8K Oct  6 18:59 CMakeLists.txt

$ ls -la .
total 4.0K
drwxr-xr-x 1 user None 0 Oct  6 19:14 ./
drwxr-xr-x 1 user None 0 Oct  6 19:14 ../

$ # run cmake

$ cmake  ../ -DCMAKE_BUILD_TYPE=SingleBuildDir -G "MSYS Makefiles"
Creating C:/test_cmake_singlebuilddir/main.c
-- The C compiler identification is GNU 13.2.0
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
Current CMAKE_BUILD_TYPE mode: SingleBuildDir
Create subdirectories in build (C:/test_cmake_singlebuilddir/build): ./Debug, ./Release
Creating top-level makefile
Initialize Debug directory
-- The C compiler identification is GNU 13.2.0
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
Current CMAKE_BUILD_TYPE mode: Debug
Proceed with rest of CMakeLists.txt - actual project setup ...
PROJECT_NAME is 'test_singlebuilddir'
-- Configuring done
-- Generating done
-- Build files have been written to: C:/test_cmake_singlebuilddir/build/Debug
Add debug build target
Initialize Release directory
-- The C compiler identification is GNU 13.2.0
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
Current CMAKE_BUILD_TYPE mode: Release
Proceed with rest of CMakeLists.txt - actual project setup ...
PROJECT_NAME is 'test_singlebuilddir'
-- Configuring done
-- Generating done
-- Build files have been written to: C:/test_cmake_singlebuilddir/build/Release
Add release build target
-- Configuring done
-- Generating done
-- Build files have been written to: C:/test_cmake_singlebuilddir/build

$ # try it out

$ make debug
make[1]: Entering directory '/c/test_cmake_singlebuilddir/build'
make[2]: Entering directory '/c/test_cmake_singlebuilddir/build'
make[3]: Entering directory '/c/test_cmake_singlebuilddir/build'
Scanning dependencies of target debug
make[3]: Leaving directory '/c/test_cmake_singlebuilddir/build'
make[3]: Entering directory '/c/test_cmake_singlebuilddir/build'
[100%] Creating the executable in the debug mode.
make[4]: Entering directory '/c/test_cmake_singlebuilddir/build/Debug'
make[5]: Entering directory '/c/test_cmake_singlebuilddir/build/Debug'
make[6]: Entering directory '/c/test_cmake_singlebuilddir/build/Debug'
Scanning dependencies of target test_singlebuilddir
make[6]: Leaving directory '/c/test_cmake_singlebuilddir/build/Debug'
make[6]: Entering directory '/c/test_cmake_singlebuilddir/build/Debug'
[ 50%] Building C object CMakeFiles/test_singlebuilddir.dir/main.c.obj
[100%] Linking C executable test_singlebuilddir.exe
make[6]: Leaving directory '/c/test_cmake_singlebuilddir/build/Debug'
[100%] Built target test_singlebuilddir
make[5]: Leaving directory '/c/test_cmake_singlebuilddir/build/Debug'
make[4]: Leaving directory '/c/test_cmake_singlebuilddir/build/Debug'
make[3]: Leaving directory '/c/test_cmake_singlebuilddir/build'
[100%] Built target debug
make[2]: Leaving directory '/c/test_cmake_singlebuilddir/build'
make[1]: Leaving directory '/c/test_cmake_singlebuilddir/build'

$ make release
make[1]: Entering directory '/c/test_cmake_singlebuilddir/build'
make[2]: Entering directory '/c/test_cmake_singlebuilddir/build'
make[3]: Entering directory '/c/test_cmake_singlebuilddir/build'
Scanning dependencies of target release
make[3]: Leaving directory '/c/test_cmake_singlebuilddir/build'
make[3]: Entering directory '/c/test_cmake_singlebuilddir/build'
[100%] Creating the executable in the release mode.
make[4]: Entering directory '/c/test_cmake_singlebuilddir/build/Release'
make[5]: Entering directory '/c/test_cmake_singlebuilddir/build/Release'
make[6]: Entering directory '/c/test_cmake_singlebuilddir/build/Release'
Scanning dependencies of target test_singlebuilddir
make[6]: Leaving directory '/c/test_cmake_singlebuilddir/build/Release'
make[6]: Entering directory '/c/test_cmake_singlebuilddir/build/Release'
[ 50%] Building C object CMakeFiles/test_singlebuilddir.dir/main.c.obj
[100%] Linking C executable test_singlebuilddir.exe
make[6]: Leaving directory '/c/test_cmake_singlebuilddir/build/Release'
[100%] Built target test_singlebuilddir
make[5]: Leaving directory '/c/test_cmake_singlebuilddir/build/Release'
make[4]: Leaving directory '/c/test_cmake_singlebuilddir/build/Release'
make[3]: Leaving directory '/c/test_cmake_singlebuilddir/build'
[100%] Built target release
make[2]: Leaving directory '/c/test_cmake_singlebuilddir/build'
make[1]: Leaving directory '/c/test_cmake_singlebuilddir/build'

$ # check where the produced executables are located:

$ find . -name '*.exe'
./CMakeFiles/3.14.3/CompilerIdC/a.exe
./Debug/CMakeFiles/3.14.3/CompilerIdC/a.exe
./Debug/test_singlebuilddir.exe
./Release/CMakeFiles/3.14.3/CompilerIdC/a.exe
./Release/test_singlebuilddir.exe

好了-这正是我一直想要的!

相关问题