最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Force CMake to generate build files (Makefile) at arbitrary point in CMakeLists.txt? - Stack Overflow

programmeradmin5浏览0评论

I have this snippet in my CMakeLists.txt of my raspberrypi/pico-sdk project, where I conditionally call the pico_sdk_init() function (that is, macro):

# ...

if(myCONDITION STREQUAL "Something")

  message("*** BEFORE pico_sdk_init() ***")
  pico_sdk_init()
  
  message("*** BEFORE return() ***")
  return() # exit for debug
  
  # other CMake conditional code commands continue here ...
  
endif() # myCONDITION STREQUAL "Something"

# ...

So, I do mkdir build && cd build in the project directory where the CMakeLists.txt is, and then I run cmake - in this case, I get output like this:

$ cmake ../ -DCMAKE_BUILD_TYPE=Debug -G "MSYS Makefiles"
...
*** BEFORE pico_sdk_init() ***
Build type is Debug
...
Using PICO_EXAMPLES_PATH from environment ...
*** BEFORE return() ***
-- Configuring done
-- Generating done
-- Build files have been written to: C:/path/to/myproject/build

After this, if I check from the ./build subfolder, I have a Makefile there (and in a whole bunch of other locations):

$ find . -name Makefile
./Makefile
./pico-sdk/docs/Makefile
./pico-sdk/Makefile
./pico-sdk/src/common/boot_picobin_headers/Makefile
...
./pico-sdk/src/rp2_common/tinyusb/Makefile
./pico-sdk/tools/Makefile

... and for the Makefile in the ./build subfolder, I have the following targets:

$ make #press [TAB] here
all                                              default_target
bs2_default/fast                                 depend
bs2_default_bin/fast                             edit_cache/fast
bs2_default_library/fast                         help
clean/fast                                       pioasmBuild/fast
cmake_check_build_system                         preinstall/fast
cmake_force                                      rebuild_cache/fast
cyw43_driver_picow_cyw43_bus_pio_spi_pio_h/fast

So, I can run, say, make pioasmBuild at this point, and it will build fine:

$ make pioasmBuild
Scanning dependencies of target pioasmBuild
[ 12%] Creating directories for 'pioasmBuild'
[ 25%] No download step for 'pioasmBuild'
...
Scanning dependencies of target pioasm
[100%] Built target pioasm
[ 87%] Performing install step for 'pioasmBuild'
[100%] Built target pioasm
Install the project...
-- Install configuration: "Release"
[100%] Completed 'pioasmBuild'
[100%] Built target pioasmBuild

$ find . -name pioasm.exe
./pioasm/pioasm.exe
./pioasm-install/pioasm/pioasm.exe

Great.

Now, let's say, I do not want to exit for debug with return() - but instead, at that point, I want to run the equivalent of make pioasmBuild: so from that point on, pioasm.exe is available for the "other CMake conditional code commands"; for that, I rewrite my snippet as:

# ...

if(myCONDITION STREQUAL "Something")

  message("*** BEFORE pico_sdk_init() ***")
  pico_sdk_init()
  
  
  execute_process(
    # this command, the equivalent of `make pioasmBuild`, fails with "Error: could not load cache"
    COMMAND ${CMAKE_COMMAND} --build . --target pioasmBuild
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
  )
  
  message("*** NOT anymore BEFORE return() ***")
  #return() # exit for debug
  
  # other CMake conditional code commands continue here ...
  
endif() # myCONDITION STREQUAL "Something"

# ...

As the comment already hints, the equivalent of make pioasmBuild at this point fails - after cleaning with rm -rf * in the ./build subdirectory, this is what I get in the cmake output:

$ cmake ../ -DCMAKE_BUILD_TYPE=Debug -G "MSYS Makefiles"
...
*** BEFORE pico_sdk_init() ***
Build type is Debug
...
Using PICO_EXAMPLES_PATH from environment ...
Error: could not load cache
*** NOT anymore BEFORE return() ***
... other CMake conditional code commands continue here ...

So, as far as I can see, this Error: could not load cache happens because at that point, the Makefile in the ./build subfolder has not been created yet!

In fact, as I understand the process at this time: the creation of that Makefile in ./build, in the previous case, was triggered by the return() early exit itself!

So my question is - is there a canonical way for us to force CMake to have configuring, generating and writing of build files to be completed at this (or arbitrary) point in the CMakeLists.txt file (using whatever data is available at that point; and at least in this case, as shown earlier, there is enough data at that point to generate a functioning Makefile) - without forcing the cmake process to exit at that point in CMakeLists.txt, but instead proceed with the remaining commands (including possibly building a target in that previously/early generated Makefile, directly from CMake)?

(Of course, in such a case of "early generation", when the CMakeLists.txt reaches its otherwise "natural" end, then all Makefiles and related build files would simply be overwritten, possibly with e.g. more targets, resulting from more data due to the execution of the remainder of the file)

I have this snippet in my CMakeLists.txt of my raspberrypi/pico-sdk project, where I conditionally call the pico_sdk_init() function (that is, macro):

# ...

if(myCONDITION STREQUAL "Something")

  message("*** BEFORE pico_sdk_init() ***")
  pico_sdk_init()
  
  message("*** BEFORE return() ***")
  return() # exit for debug
  
  # other CMake conditional code commands continue here ...
  
endif() # myCONDITION STREQUAL "Something"

# ...

So, I do mkdir build && cd build in the project directory where the CMakeLists.txt is, and then I run cmake - in this case, I get output like this:

$ cmake ../ -DCMAKE_BUILD_TYPE=Debug -G "MSYS Makefiles"
...
*** BEFORE pico_sdk_init() ***
Build type is Debug
...
Using PICO_EXAMPLES_PATH from environment ...
*** BEFORE return() ***
-- Configuring done
-- Generating done
-- Build files have been written to: C:/path/to/myproject/build

After this, if I check from the ./build subfolder, I have a Makefile there (and in a whole bunch of other locations):

$ find . -name Makefile
./Makefile
./pico-sdk/docs/Makefile
./pico-sdk/Makefile
./pico-sdk/src/common/boot_picobin_headers/Makefile
...
./pico-sdk/src/rp2_common/tinyusb/Makefile
./pico-sdk/tools/Makefile

... and for the Makefile in the ./build subfolder, I have the following targets:

$ make #press [TAB] here
all                                              default_target
bs2_default/fast                                 depend
bs2_default_bin/fast                             edit_cache/fast
bs2_default_library/fast                         help
clean/fast                                       pioasmBuild/fast
cmake_check_build_system                         preinstall/fast
cmake_force                                      rebuild_cache/fast
cyw43_driver_picow_cyw43_bus_pio_spi_pio_h/fast

So, I can run, say, make pioasmBuild at this point, and it will build fine:

$ make pioasmBuild
Scanning dependencies of target pioasmBuild
[ 12%] Creating directories for 'pioasmBuild'
[ 25%] No download step for 'pioasmBuild'
...
Scanning dependencies of target pioasm
[100%] Built target pioasm
[ 87%] Performing install step for 'pioasmBuild'
[100%] Built target pioasm
Install the project...
-- Install configuration: "Release"
[100%] Completed 'pioasmBuild'
[100%] Built target pioasmBuild

$ find . -name pioasm.exe
./pioasm/pioasm.exe
./pioasm-install/pioasm/pioasm.exe

Great.

Now, let's say, I do not want to exit for debug with return() - but instead, at that point, I want to run the equivalent of make pioasmBuild: so from that point on, pioasm.exe is available for the "other CMake conditional code commands"; for that, I rewrite my snippet as:

# ...

if(myCONDITION STREQUAL "Something")

  message("*** BEFORE pico_sdk_init() ***")
  pico_sdk_init()
  
  
  execute_process(
    # this command, the equivalent of `make pioasmBuild`, fails with "Error: could not load cache"
    COMMAND ${CMAKE_COMMAND} --build . --target pioasmBuild
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
  )
  
  message("*** NOT anymore BEFORE return() ***")
  #return() # exit for debug
  
  # other CMake conditional code commands continue here ...
  
endif() # myCONDITION STREQUAL "Something"

# ...

As the comment already hints, the equivalent of make pioasmBuild at this point fails - after cleaning with rm -rf * in the ./build subdirectory, this is what I get in the cmake output:

$ cmake ../ -DCMAKE_BUILD_TYPE=Debug -G "MSYS Makefiles"
...
*** BEFORE pico_sdk_init() ***
Build type is Debug
...
Using PICO_EXAMPLES_PATH from environment ...
Error: could not load cache
*** NOT anymore BEFORE return() ***
... other CMake conditional code commands continue here ...

So, as far as I can see, this Error: could not load cache happens because at that point, the Makefile in the ./build subfolder has not been created yet!

In fact, as I understand the process at this time: the creation of that Makefile in ./build, in the previous case, was triggered by the return() early exit itself!

So my question is - is there a canonical way for us to force CMake to have configuring, generating and writing of build files to be completed at this (or arbitrary) point in the CMakeLists.txt file (using whatever data is available at that point; and at least in this case, as shown earlier, there is enough data at that point to generate a functioning Makefile) - without forcing the cmake process to exit at that point in CMakeLists.txt, but instead proceed with the remaining commands (including possibly building a target in that previously/early generated Makefile, directly from CMake)?

(Of course, in such a case of "early generation", when the CMakeLists.txt reaches its otherwise "natural" end, then all Makefiles and related build files would simply be overwritten, possibly with e.g. more targets, resulting from more data due to the execution of the remainder of the file)

Share Improve this question asked 2 hours ago sdbbssdbbs 5,4467 gold badges57 silver badges118 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

There's no way to do this, since there may be other information about the targets that comes later in the CMakeLists.txt files. What you want to do instead is add a dependency on pioasmBuild anywhere that needs it, since that set up your actual build dependencies properly.

add_dependencies(my_target pioasmBuild)

However, I'd recommend building pioasmBuild separately and using find_executable instead. If you're cross-compiling, you'd build targets using the cross-compiler and thus can't use them on your native machine.

发布评论

评论列表(0)

  1. 暂无评论