CMake generator expression evaluated to "" instead of nothing - cmake

I'm using generator expressions in a custom command to compile hlsl shaders:
add_custom_command(TARGET Shaders
COMMAND vendor/shader-compiling/fxc.exe /nologo /Emain /Tvs_5_0 $<$<CONFIG:Debug>:/Od> /Zi /Fo ${TARGET_SHADER_PATH}/hlsl/${FILE_WE}_vs.cso /Fd ${CMAKE_BINARY_DIR}/${FILE_WE}_vs.pdb ${TARGET_SHADER_PATH}/hlsl/${FILE_WE}_vs.hlsl
COMMAND vendor/shader-compiling/fxc.exe /nologo /Emain /Tps_5_0 $<$<CONFIG:Debug>:/Od> /Zi /Fo ${TARGET_SHADER_PATH}/hlsl/${FILE_WE}_fs.cso /Fd ${CMAKE_BINARY_DIR}/${FILE_WE}_fs.pdb ${TARGET_SHADER_PATH}/hlsl/${FILE_WE}_fs.hlsl
MAIN_DEPENDENCY ${FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Compiling HLSL shader ${TARGET_SHADER_PATH}/hlsl/${FILE_WE}.hlsl"
VERBATIM)
and in debug mode everything works fine.
However, in release mode, my expected result is the /Od flag does not get included in the command at all. However, what ended up happening is $<$<CONFIG:Debug>:/Od> gets evaluated to two double quotes and the command doesn't work.
Any ideas on why this is happening?

Just in case anybody finds this useful, I solved the problem by adding COMMAND_EXPAND_LISTS to my add_custom_command command. Not sure why that works but it does get rid of the empty pair of quotes in the middle of the command therefore the command works.

Related

Cmake add_custom_command is never running

My question is very similar to cmake: add_custom_command / add_custom_target ignoring dependency
But the answer specified does not solve my issue, and also it is for a newer version of cmake (3.20)
I want some files (shader files) to be copied to the executable directory every time the shader source changes
So I have the following code in cmake:
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/Shaders.txt
COMMAND ${CMAKE_COMMAND} -E echo "Actually Copying shaders"
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/assets/ $<TARGET_FILE_DIR:Editor>/assets
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/Shaders.txt
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/assets
)
add_custom_target(CopyShaders ALL DEPENDS ${CMAKE_BINARY_DIR}/Shaders.txt)
Now, as I understand, CopyShaders will always be built (since it is always out of date), but Shaders.txt should only be built once (after the shader source is changed), after which it is up to date
I'm trying to build the target CopyShaders using cmake --build build --target CopyShaders
If I'm using MinGW, then "Actually copying shaders" never gets printed if Shaders.txt is present, even if the assets folder containing the shaders has been modified
If I'm using MSVC, I get the following warning on the terminal:
warning MSB8064: Custom build for item "D:\Acads\Programming\opengl\SummerOfCode\build\CMakeFiles\05fb3856b7a5e1f6ce1ea66ca9091779\Shaders.txt.rule" succeeded, but specified dependency "d:\acads\programming\opengl\summerofcode\editor\assets" does not exist. This may cause incremental build to work incorrectly. [D:\Acads\Programming\opengl\SummerOfCode\build\Editor\CopyShaders.vcxproj]
Again, I do have the folder existing
I figured it out
DEPENDS should only take as input files, not folders
Replacing it with all the files inside /assets works

Run PowerShell or Shell script from CMake

I have a (power)shell script that generates a version file used in other source files in the project.
How can I "register" this script to be used with CMake in build time? Here is what I have tried:
function(version)
set(SRC version.h)
set(VERSION_CMD ${CMAKE_SOURCE_DIR}/fw_lib/version/version.ps1)
ADD_CUSTOM_TARGET(version DEPENDS ${SRC})
ADD_CUSTOM_COMMAND(
OUTPUT ${SRC} COMMAND ${VERSION_CMD}
${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}
)
endfunction(version)
Note that ${CMAKE_SOURCE_DIR} and ${CMAKE_BINARY_DIR} are input arguments to the script.
I get the following error:
process_begin: CreateProcess(....) failed.
make (e=193): Error 193
How can I make this work?
Maybe it is too late, but for future:
# find Powershell executable
find_program(POWERSHELL_PATH NAMES powershell)
add_custom_command(
TARGET "program"
POST_BUILD
COMMAND ${POWERSHELL_PATH} "Some Powershell command")

how to remove ":" of cmake TARGET_OBJECTS, and use it in custom command

I want to use objs in COMMAND ld, but I cannot remove ";" in objs.
How can I remove ";"?
or have any other method to fix it?
CMakeLists.txt
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
set(SOURCES
lib1_public.h
lib1_public.cpp
lib.h
lib.c)
add_library(objlib1 OBJECT ${SOURCES})
set(objs_list "$<TARGET_OBJECTS:objlib1>")
string(REPLACE ";" " " myobjs "${objs_list}")
add_custom_command(
OUTPUT lib1_hidden.o
COMMAND ld -r "${myobjs}" -o lib1.o
COMMAND objcopy --localize-hidden lib1.o lib1_hidden.o
COMMENT "Building mylib1.a")
add_library(mylib1 STATIC lib1_hidden.o)
output
[100%] Building mylib1.a
cd /home/yongle.xh/tmp/cmake_test/lib/lib1 && ld -r /home/yongle.xh/tmp/cmake_test/lib/lib1/CMakeFiles/objlib1.dir/lib1_public.cpp.o;/home/yongle.xh/tmp/cmake_test/lib/lib1/CMakeFiles/objlib1.dir/lib.c.o -o lib1.o
I believe what is missing here is the COMMAND_EXPAND_LISTS option in add_custom_command. Try something along the lines of
add_custom_command(
OUTPUT lib1_hidden.o
COMMAND ld -r $<TARGET_OBJECTS:objlib1> -o lib1.o
COMMAND objcopy --localize-hidden lib1.o lib1_hidden.o
COMMENT "Building mylib1.a"
COMMAND_EXPAND_LISTS)
$<TARGET_OBJECTS:objlib1> is a generator expression (aka "genex"), which means it only gets evaluated at generate time: after CMake has processed all its input files and has started generating the buildsystem. While CMake is still processing input, it's a literal string. Your string(REPLACE) therefore cannot have any effect, because the string $<TARGET_OBJECTS:objlib1> does not contain any semi-colons.
However, I don't think you actually need to remove them in any way. What causes them to appear on the command line is the fact that you're quoting the expansion of myobjs in the COMMAND, which means "treat this list after genex expansion as a single argument for the command." That's most likely not what you want. To pass the objects as one argument each, simply remove the quotes (and also the unneeded string command):
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
set(SOURCES
lib1_public.h
lib1_public.cpp
lib.h
lib.c)
add_library(objlib1 OBJECT ${SOURCES})
add_custom_command(
OUTPUT lib1_hidden.o
COMMAND ld -r $<TARGET_OBJECTS:objlib1> -o lib1.o
COMMAND objcopy --localize-hidden lib1.o lib1_hidden.o
COMMENT "Building mylib1.a")
add_library(mylib1 STATIC lib1_hidden.o)

Error with variables when invoking CMake from CMake

I need to invoke cmake from within cmake so that I can have binaries built before project files are generated. I have the following CmakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(StarEngine)
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
#copy the other cmake file into where we'd like to invoke cmake
configure_file(deps-CMakeLists.txt deps/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps)
#eventually binaries will be built, for now this doesn't accomplish anything
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps)
And its friend, deps-CmakeLists.txt, a test script:
set(GENERATED_DIR "test")
MESSAGE( STATUS ${GENERATED_DIR} )
In the following file structure:
Project
build
Code
CmakeLists.txt
deps-CmakeLists.txt
No matter what I put in for the variable value, it is blank when displayed in MESSAGE. I imagine this is weird behavior resulting from invoking cmake from cmake. I had a bunch of other strange errors to, but I suspect if I can figure out this one that will help crack them all.
Thanks to #Florian, the problem was with variable replacement and I needed to add the COPYONLY option to configure_file

Using cmake with a custom file generator

I'd like to use CMake to generate obfuscated lua files for delivery. For the life of me I cannot get add_custom_command + add_custom_target to build these files for me. There's something I'm missing.
ADD_CUSTOM_TARGET(LUABIND_COMPILED_FILES ALL)
FOREACH(F ${LUA_SCRIPT_FILES})
ADD_CUSTOM_COMMAND(
OUTPUT ${LUA_COMPILED_SCRIPTS}/${F}
COMMAND ${LUAC} -o ${LUA_COMPILED_SCRIPTS}/${F}
COMMENT "Compiling ${F} to binary"
ADD_DEPENDENCIES(LUABIND_COMPILED_FILES ${LUA_COMPILED_SCRIPTS}/${F})
ENDFOREACH()
For some reason when I run cmake + make the output tells me there's nothing to be done for target LUABIND_COMPILED_FILES. Am I missing something here? Thanks in advance.
The ADD_DEPENDENCIES command can only be used to add dependencies between top-level targets. The ADD_CUSTOM_COMMAND command however generates output files, but does not add new targets.
To make a custom target depend on generated files, use the DEPENDS options of the add_custom_target command:
set (LUA_COMPILED_FILES "")
foreach(F ${LUA_SCRIPT_FILES})
add_custom_command(
OUTPUT "${LUA_COMPILED_SCRIPTS}/${F}"
COMMAND ${LUAC} -o "${LUA_COMPILED_SCRIPTS}/${F}"
COMMENT "Compiling ${F} to binary")
list (APPEND LUA_COMPILED_FILES "${LUA_COMPILED_SCRIPTS}/${F}")
endforeach()
add_custom_target(LUABIND ALL DEPENDS ${LUA_COMPILED_FILES})