简体   繁体   中英

How to insert powershell command inside cmake expression

I am creating a draw function that uses imgui API to show graphics. This function is compiled as a DLL and dynamically loaded at runtime each time it is recompiled. It works well in release mode but I want to be able to debug it. In debug a.pdb file is created and locked by the debugger such as when running my program in the debugger, the linker is unable to overwrite the previous PDB file and the library is not created

The idea is simple: for each compilation generate a new .pdb file with the name based on the timestamp.

The PowerShell command I use to give the timestamp is get-date -uformat %H%M%S . The linker argument to set the PDB file name is /PDB:

I want CMake to add the following option to the linker flag: /PDB:file_name_$(get-date -uformat %H%M%S).pdb .

And this is where it gets tricky: CMake always interprets the $() and in the result, the whole expression is replaced by nothing because what is inside my $() has no meaning for CMake.

How can I instruct CMake to output the "$" the "(" and the ")" as characters and not interpret it?

The best I have done so far is to create a variable for those characters. It works well when putting the result in a variable but the string is always interpreted inside add_link_options :

    set(DOLLAR_LITERAL "$")
    set(OPEN_CURLY_BRACKET_LITERAL "(")
    set(CLOSE_CURLY_BRACKET_LITERAL ")")
    set(TIMESTAMP_PDB "/PDB:hot_reload_draw_${DOLLAR_LITERAL}${OPEN_CURLY_BRACKET_LITERAL} 
    get-date -uformat %H%M%S${CLOSE_CURLY_BRACKET_LITERAL}.pdb")
    message(${TIMESTAMP_PDB})
    target_link_options(hot_reload_draw PRIVATE ${TIMESTAMP_PDB})

when configuring I have the write output displayed:

-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19045.
-- BIOS file already downloaded
/PDB:hot_reload_draw_$( get-date -uformat %H%M%S).pdb
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Adrien COURNAND/Documents/Informatique/C++/E5150/cmake-build-debug

[Finished]

and if I echo the message it gives the right output:

echo /PDB:hot_reload_draw_$( get-date -uformat %H%M%S).pdb
/PDB:hot_reload_draw_135735.pdb

But at compilation the value inside $() is discarded:

/PDB:"hot_reload_draw_.pdb"

I want it to be "/PDB:hot_reload_draw_$(get-date -uformat %H%M%S).pdb" so it is interpreted by the PowerShell


edit

following what @Milan said, I tried to use [=[...]=] quoting and switched to Ninja generator, and it looks like opened the door of weirdness...

First of all to use Ninja as build system I have to call cmake from an x64 Developper Cmd Prompt.

I edited my CMakeLists.txt to be target_link_options(hot_reload_draw PRIVATE [=[/PDB:gui\hot_reload_draw_$(get-date -uformat %H%M%S).pdb]=]) , and with this CMakeLists.txt I have different linker arguments depending of the generator (but still not the one I want):

  • /PDB:"gui\hot_reload_draw_.pdb" with "Visual Studio 17 2022" generator (maybe visual studio generator spawn cmd process and thus the $() is well outputted to the script file but interpreted as empty by the cmd interpreter)
  • "/PDB:gui\hot_reload_draw_$$(get-date -uformat %H%M%S).pdb" with Ninja as the generator almost what I want but for some reason, the "$" symbol is doubled
  • ``

Take a look at bracket arguments . I assume it is what you are looking for. Ie you want to enclose your argument in [=[ ]=] - it should skip the evaluation.

EDIT: Here is a minimal example

set(FOO "BAR")
message(STATUS ${FOO})
message(STATUS [=[${FOO}]=])

This should output:

BAR
${FOO}

I achieved what I wanted but I had to trigger a configuration path each time I want a rebuild.

I edited the CMakeLists.txt :

if(HOT_RELOAD_PDB_NAME)
    message(INFO "Build with PDB name ${HOT_RELOAD_PDB_NAME}")
    set_property(TARGET hot_reload_draw PROPERTY PDB_NAME ${HOT_RELOAD_PDB_NAME})
endif()

And then I created a script that computes the value of HOT_RELOAD_PDB_NAME and then trigger a new CMake configuration+build path for my library:

@echo off

for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"

set "datestamp=%YYYY%%MM%%DD%" & set "timestamp=%HH%%Min%%Sec%"
set "fullstamp=%YYYY%-%MM%-%DD%_%HH%-%Min%-%Sec%"

cmake -B %1 -DHOT_RELOAD_PDB_NAME="hot_reload_draw_%timestamp%"
cmake --build %1 --target hot_reload_draw --verbose

When I want a rebuild I simply call it and it does the job. When I issue a dir of binary dir I get:

13/01/2023  18:11         2 134 016 hot_reload_draw_181137.pdb
13/01/2023  18:36         3 274 752 hot_reload_draw_182811.pdb
13/01/2023  18:42         2 732 032 hot_reload_draw_183735.pdb
13/01/2023  18:42         2 134 016 hot_reload_draw_184237.pdb
13/01/2023  18:43         2 134 016 hot_reload_draw_184321.pdb
13/01/2023  18:49         2 134 016 hot_reload_draw_184953.pdb
13/01/2023  18:50         2 134 016 hot_reload_draw_185003.pdb

and it is compatible with PowerShell or Cmd.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM