cmake 'add_custom_command' to pre-process header files? - makefile

i'm working on a project requiring cmake. i'd like to add some custom rules to my makefile, but can't quite get my head around how to do it.
both c source files and header files are in the same directory. also in this same directory are a number of .def files, which are the sources for some of the header files #included in the source during compilation.
if i were to do this in a makefile, i'd use a simple rule like
.SUFFIXES: .def
.def.h:
$(PREPROC) $< > $#
how can i do this with cmake ??
i've tried various permutations of the following, both with and without cmake working directory specifications :
add_custom_command(
OUTPUT vvr_const.h
PRE_BUILD
COMMAND preproc vvr_const.def > vvr_const.h
DEPENDS vvr_const.def
)
add_custom_target(vvr_const.h DEPENDS vvr_const.def)
but the header file isn't generated by the time the c source file is compiled, so the compile fails. i've also tried a variation where i replace the last line above with
set_property(SOURCE main.c APPEND PROPERTY OBJECT_DEPENDS vvr_const.h)
in this case, the header file is correctly generated in advance, but make can't find it, and complains that there's no rule to make the target .h.
ideally this would be a general rule, like the make rule above, but i'm not opposed to making a separate rule for each of the .def files if that's what it takes.
cheers.

There are 2 problems with the add_custom_command approach you present:
You did not specify a working directory; by default the command is run in the build directory, not in the source directory.
You rely on shell functionality here (the redirect to a file). Even though this probably still works. You should go with an approach that does not rely on the shell.
To solve issues 1 and 2 I recommend creating a seperate cmake script file receiving the absolute paths to input and output files and using those in the custom command. This allows you to use execute_process to specify the file to write without relying on the platform.
preprocess_def.cmake
# preprocess def file
# parameters INPUT_FILE and OUTPUT_FILE denote the file to use as source
# and the file to write the results to respectively
# use preproc tool to get data to write to the output file
execute_process(COMMAND preproc "${INPUT_FILE}"
RESULT_VARIABLE _EXIT_CODE
OUTPUT_FILE "${OUTPUT_FILE}")
if (_EXIT_CODE)
message(FATAL_ERROR "An error occured when preprocessing the file ${INPUT_FILE}")
endif()
CMakeLists.txt
set(_INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vvr_const.def")
set(_OUTPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vvr_const.h")
# not necessary to use build event here, if we mark the output file as generated
add_custom_command(OUTPUT "${_OUTPUT_FILE}"
COMMAND "${CMAKE_BUILD_TOOL}" -D "OUPUT_FILE=${_OUTPUT_FILE}" -D "INPUT_FILE=${_INPUT_FILE}" -P "${CMAKE_CURRENT_SOURCE_DIR}/preprocess_def.cmake"
DEPENDS "${_INPUT_FILE}")
add_executable(my_target vvr_const.h ...)
set_source_files_properties(vvr_const.h PROPERTIES GENERATED 1)

Documentation from cmake:
PRE_BUILD
On Visual Studio Generators, run before any other rules are executed within the target. On other generators, run just before PRE_LINK commands.
So possibly your command is just running too late.

Related

Cmake doesn't recognize custom command as valid source

I have a problem modifying existing CMake based build-system. All I want to do is add different build rule for some of .c files. For the sake of this problem, I will focus on only one file.
The simplified directories tree looks like this
Project:
./src
- file_of_interest.c
- CmakeFiles.txt
other_files.c
CmakeFiles.txt
So in order to compile file_of_interest.c in a different way I do:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/file_of_interest.s
COMMAND xt-xcc -S ${CMAKE_CURRENT_SOURCE_DIR}/file_of_interest.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/file.c
COMMENT "Generating file_of_interest.s"
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/file_of_interest.c.o
COMMAND xt-xcc ${CMAKE_CURRENT_BINARY_DIR}/file_of_interest.s -o file_of_interest.c.o -c
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/file_of_interest.s
COMMENT "Generating file_of_interest.c.o"
)
message(" ${CMAKE_CURRENT_BINARY_DIR} \n ${CMAKE_CURRENT_SOURCE_DIR}")
target_sources(target_name PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/file_of_interest.c.o)
As you can see I used CMake's message() to print paths to be sure all is set up properly. It should work, but it doesn't! I expect CMake to register file_of_interest.c.o as source of target_name (and this is probably working), then "tie" it with my custom command which produces OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/file_of_interest.c.o and then to tie again ${CMAKE_CURRENT_BINARY_DIR}/file_of_interest.c.o with OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/file_of_interest.s and this certainly doesn't happen as CMake shows error message saying CMake Error at CMakeLists.txt:170 (add_executable): Cannot find source file: path/file_of_interest.c.o
The path is OK. So the question is why does CMake cannot recognize recipes for that file?
It seems that you create an executable (call add_executable) in the top-level CMakeLists.txt, but add_custom_command are called from the subdirectory (src/CMakeLists.txt).
This doesn't work: when CMake processes add_executable and searches for the commands generating its sources, it sees only add_custom_commands created in the same CMakeLists.txt.
From the add_custom_command documentation:
A target created in the same directory (CMakeLists.txt file) that specifies any output of the custom command as a source file is given a rule to generate the file using the command at build time.
It is unrelated that target_sources is called from the same directory as add_custom_command: the target is created by add_executable command, and target_sources just modifies its properties.

Get rid of CMake Rules folder

Is there a way to get rid of the CMake Rules folders in targets in Visual Studio?
In this case the game target uses cotire for precompiled header support and the omg target has a custom command that parses the .mix file and outputs the ..._gen.h file.
Also would it be possible to remove the CMakeLists.txt file from there too? I know it's there for convenience but in my workflow it isn't that useful.
EDIT: Started a second bounty because I really need this - these "CMake Rules" folders are bloating my solution explorer because I have 100+ projects which all have them!
I would accept anything - a CMake way, a VS way (some "solution explorer view" or macro or whatever)...
EDIT 2:
here is sort-of the cmake for the omg target:
add_library(omg SHARED D:/omg.cpp D:/omg.mix)
add_custom_command(OUTPUT D:/omg_gen.h MAIN_DEPENDENCY D:/omg.mix COMMAND python D:/mixify.py D:/omg.mix D:/omg_gen.h)
add_custom_target(${target}_gen_${mix_name_only} DEPENDS ${gen_header})
add_dependencies(omg omg_gen)
target_sources(omg PUBLIC D:/omg_gen.h)
so omg_gen.h is generated from omg.mix and then included in omg.cpp
The .rule files are needed by CMake to attach the custom commands to some "dummy" self-generated file, if there are no input files given. You can see this when you look at the .rule file properties of your Visual Studio project in question (see Custom Build Tool/General/Command Line).
If you're not changing the CMake script code containing those target, you can't get rid of them.
You can only move them into the project's root source folder or any other folder you specify.
I've successfully tested the following example:
cmake_minimum_required(VERSION 2.8)
project(NoRulesSourceGroup NONE)
# Overwrite the rule for "CMake Rules" with do-not-match-anything (-> root)
source_group("CMake Rules" REGULAR_EXPRESSION "^$")
# Move ".rule" files somewhere else
source_group("Some Other Source Group" REGULAR_EXPRESSION "\\.rule$")
add_custom_target(
${PROJECT_NAME}
COMMAND ${CMAKE_COMMAND} -E echo "Hello World"
)
Edit: You could also combine the above regular expression with a match for CMakeLists.txt:
source_group("Some Other Source Group" REGULAR_EXPRESSION "CMakeLists\\.txt|\\.rule$")
Edit: If you can modify your CMake script code, you should add to your add_custom_command() call:
MAIN_DEPENDENCY
Specify the primary input source file to the command. This is treated just like any value given to the DEPENDS option but also suggests to Visual Studio generators where to hang the custom command. At most one custom command may specify a given source file as its main dependency.
In your case you won't even need the additional custom target since you have a dependency through the header file. I've successfully tested the following derived from your question's example:
file(WRITE omg.cpp "")
file(WRITE omg.mix "")
add_library(omg SHARED omg.cpp omg.mix)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/omg_gen.h
MAIN_DEPENDENCY omg.mix
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/omg.mix ${CMAKE_CURRENT_BINARY_DIR}/omg_gen.h
)
target_sources(omg PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/omg_gen.h)
References
source_group()
Source/cmMakefile.cxx

About a deep header file in Makefile

Say I have a header file which is included by many source files, maybe with a very deep hierarchy. It is very boring to list this common header file in the prerequisites of each source object, and not sure whether there is an elegant solution. Thanks!
You can generate such dependencies with gcc -M. From TFM:
-M Instead of outputting the result of preprocessing, output a rule suitable for make describing the dependencies of the main source file. The preprocessor outputs one make rule containing the object file name for that source file, a colon, and the names of all the included files, including those coming from -include or -imacros command line options.
Also see Generating Prerequisites Automatically.

Make gcc put relative filenames in debug information

The project I'm compiling uses CMake, which loves absolute pathnames.
When I compile with debugging information enabled, gcc puts those long names into .debug_str sections, which is bad for debugging. I'd like to have short relative-to-project-root pathnames there instead.
Is there some option to tell gcc to strip some part of pathname before emitting debug data? Or, maybe, there is some tool that could do that on compiled binaries?
I've tried using SET(CMAKE_USE_RELATIVE_PATHS ON) (which seems to be frowned upon by devs) option, but as I'm using out-of-source builds, pathnames are still not in the form I'd want them to be. I.e. they're ./../src/mod_foo/foo.c instead of mod_foo/foo.c.
You can use the -fdebug-prefix-map flag to remap the debugging information paths. For example, to make the paths relative to the build location use: -fdebug-prefix-map=/full/build/path=.
You can set the RULE_LAUNCH_COMPILE property of a CMake target to have CMake invoke a shell script which transforms the source file path to a project relative path before invoking gcc. Use the CMake function configure_file to generate a shell script which knows about the PROJECT_SOURCE_DIR and PROJECT_BINARY_DIR of your project.
In your outermost CMakeLists.txt add the following code:
configure_file(
"${PROJECT_SOURCE_DIR}/gcc_debug_fix.sh.in"
"${PROJECT_BINARY_DIR}/gcc_debug_fix.sh"
#ONLY)
add_executable (MyExecutable ...)
set_target_properties(MyExecutable PROPERTIES
RULE_LAUNCH_COMPILE "${PROJECT_BINARY_DIR}/gcc_debug_fix.sh")
The following template shell script gcc_debug_fix.sh.in needs to go to the root directory of the CMake project:
#!/bin/sh
PROJECT_BINARY_DIR="#PROJECT_BINARY_DIR#"
PROJECT_SOURCE_DIR="#PROJECT_SOURCE_DIR#"
# shell script invoked with the following arguments
# $(CXX) $(CXX_DEFINES) $(CXX_FLAGS) -o OBJECT_FILE -c SOURCE_FILE
# extract parameters
SOURCE_FILE="${#: -1:1}"
OBJECT_FILE="${#: -3:1}"
COMPILER_AND_FLAGS=${#:1:$#-4}
# make source file path relative to project source dir
SOURCE_FILE_RELATIVE="${SOURCE_FILE:${#PROJECT_SOURCE_DIR} + 1}"
# make object file path absolute
OBJECT_FILE_ABSOLUTE="$PROJECT_BINARY_DIR/$OBJECT_FILE"
cd "$PROJECT_SOURCE_DIR"
# invoke compiler
exec $COMPILER_AND_FLAGS -c "${SOURCE_FILE_RELATIVE}" -o "${OBJECT_FILE_ABSOLUTE}"
The shell script uses the information from the variables PROJECT_BINARY_DIR and PROJECT_SOURCE_DIR to transform the path of the source file to a path relative to the project root and the object file's path to an absolute path. Because gcc gets passed a project relative path now, .debug_str should use that path, too.
The following caveats apply:
Be sure to set the executable bit of gcc_debug_fix.sh.in.
For the script to work CMAKE_USE_RELATIVE_PATHS has to set to OFF again.
The script makes assumptions about the location of the file paths on the command line. This may not work if CMake uses a different rule to invoke the compiler. A more robust solution would be to scan the script arguments for the -o and -c flags.
If I really couldn't fix the make file/tool to do this properly, I would write a wrapper script for gcc that recognises absolute pathnames and converts then to relative ones.
It might look something like this in bash:
#!/bin/bash
out=()
for arg; do
out=("${out[#]}" $(echo "$arg" | sed 's:/my/absolute/directory/:../:'))
done
exec gcc "${out[#]}"
If your source directory has subdirectories then you'll need to handle those carefully, but the above should work for a flat source directory. I've not tested it though, and I wouldn't be surprised if I've got the quoting wrong, but that'll only be a problem if you have pathnames with spaces in. It also doesn't handle parameters like -I/whatever/include, but you can fix that.

Using make to add m4 preprocessing to an arbitrary language

We have an ActionScript (Flex) project that we build using GNU make. We would like to add an M4 preprocessing step to the build process (e.g., so that we can create an ASSERT() macro that includes file and line numbers).
We are having remarkable difficulty.
Our current strategy is:
Create a directory "src/build" (assuming source code is in src/ and subdirectories).
Within src/build, create a Makefile.
Run make inside src/build.
The desired behavior is, make would then use the rules we write to send the *.as files src/ and its subdirs, creating new *.as files under build. For example:
src/bar.as -> m4 -> src/build/bar.as
src/a/foo.as -> m4 -> src/build/a/foo.as
The obvious make rule would be:
%.as : ../%.as
echo "m4 --args < $< > $#"
This works for bar.as but not a/foo.as, apparently because make is being "smart" about splitting and re-packing directories. make -d reveals:
Trying implicit prerequisite `a/../foo.as'.
Looking for a rule with intermediate file `a/../foo.as'.
but we want the prerequisite to be "../a/foo.as". This (what we don't want) is apparently documented behavior (http://www.gnu.org/software/make/manual/make.html#Pattern-Match).
Any suggestions? Is it possible to write a pattern rule that does what we want?
We've tried VPATH also and it does not work because the generated .as files are erroneously satisfying the dependency (because . is searched before the contents of VPATH).
Any help would be greatly appreciated.
One option is to use a different extension for files that haven't been preprocessed. Then you can have them in the same directory without conflict.
As Anon also said, your source code is no longer Flex - it is 'to be preprocessed Flex'. So, use an extension such as '.eas' (for Extended ActionScript) for the source code, and create a 'compiler' script that converts '.eas' into '.as' files, which can then be processed as before.
You may prefer to have the Extended ActionScript compiler do the whole compilation job - taking the '.eas' direct to the compiled form.
The main thing to be wary of is ensuring that '.eas' files are considered before the derived '.as' files. Otherwise, your changes in the '.eas' files will not be picked up, leading to hair-tearing and other undesirable behaviours (head banging, as in 'banging head against wall', for example) as you try to debug code that hasn't changed even though the source has.

Resources