Modify source files during cmake build - bash

I need to modify some of my project's sources during compilation. It'd be better if I get to modify them between preprocessing and compilation, but I know it's harder to achieve (The solution proposed here is not optimal for me) so I can settle with a pre-preprocessing step.
Since the source files are to be modified, I need to create a copy of them, modify that copy then run the build on this copy. My current solution is:
Prior to cmake invocation, I copy most of the project root contents' to a separate directory. This is required because there are many script invocations during the build so I need to keep most of the project hierarchy intact. Since there are many files and many of them will not be modified, I first copy all files as symbolic links (cp -sR), then hard copy all .c and .h files. Then I just cd to that directory and invoke cmake and make as usual.
The problem here is that since cmake is not aware that it's working on copies of the actual source, the generated Makefile doesn't check whether the actual source was updated. So I need a full rebuild (Full project tree copy and cmake invocation) whenever I modify a single source file.
This can probably be solved by adding a custom command for each hard copied source file that depends on the actual source file, and recopies it after being modified. I guess it's okay, but it really is... ugly, and requires lots of cmake additions. I don't think what I'm trying to do is so exotic, so I believe there is a better option that could work with little changes to my cmake. I'd also like to hear ideas regarding post preprocessor step invocation.
EDIT: A simplified example case.
This is the project tree:
CMakeLists.txt
src/
CMakeLists.txt
file1.c
file1.c
python/
script.py
The root CMakeLists.txt is add_subdirectory(src/). The src/CMakeLists.txt is add_executable(myexe file1.c file2.c).
I need to execute python python/script.py for each source file, so it should be called on src/file1.c and src/file2.c.
My current solution is a build script as follows:
rm -r build_dir
mkdir build_dir
cp -rt build_dir CMakeLists.txt src/ python/
cd build_dir
cmake .
make # ...
Plus an invocation of python/script.py (prebuild add_custom_command) which globs for the relevant files itself, then processes them.

Related

Calling existing make command in cmake file

I have a large project with multiple subdirectories. In the parent directory, I have a CMakeLists.txt file which calls functions defined in other cmake files in the same parent directory. I have a custom Makefile in one of the subdirectories that contains some target "run". When I call cmake from the parent directory, I want the "run" target located in the subdirectory makefile to execute. How should I do this ?
I understand that some people have suggested to use add_custom_target and add_custom_command, but I am still confused as to how to apply these commands to accomplish this task.
If you know, which file(s) are produced by Makefile in the subdirectory, and want to depend on these files, use add_custom_command:
add_custom_command(OUTPUT <output-file>
COMMAND make run
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/<subdir>
)
This assumes that your CMakeLists.txt have a target, which depends or uses given file.
Otherwise, if you do not care which files are produced by Makefile, use add_custom_target:
add_custom_target(<target_name> COMMAND make run
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/<subdir>
)
In both cases WORKING_DIRECTORY specifies directory which should be current for command executed.
If you want the target (in the second case) to be executed by default, add ALL option before the COMMAND.

Find and move files with extension at build time using CMake

I'm currently trying to use Gcov and Gcovr from CMake on Windows using MinGW.
Compiling the files with the right flags works like a charm.
However, CLion uses an out-of-source build which Gcov does not understand.
On Linux I used the following to copy all the *.gcda and *.gcno to the CMAKE_SOURCE_DIR from CMAKE_BINARY_DIR subfolders:
set(GCOV_DATA_DIR "${CMAKE_SOURCE_DIR}/gcov_data")
add_custom_target(prepare_coverage
# Copy necessary files to CMAKE_SOURCE_DIR
COMMAND ${CMAKE_COMMAND} -E make_directory ${GCOV_DATA_DIR}
COMMAND find ${CMAKE_BINARY_DIR} -name \"*.gcda\" -o -name \"*.gcno\" | xargs -l -i cp {} "${GCOV_DATA_DIR}"
)
Note that test binaries are executed in CMAKE_BINARY_DIR.
This works pretty well and I can call Gcovr with some additional flags afterwards to get a nice report.
However, on Windows I do not have xargs (I was already supprised that find did work).
To make this CMake command platform-independent I'm looking for a way to make CMake find and copy/move the files during build time (similar to making the directory).
Can anyone tell me if this is possible and how I should do this?
Of course I can always install additional programs or scripts, but I'd rather solve this within CMake instead of having to instruct all the developers to install different tools.
If you don't use CMAKE_RUNTIME_OUTPUT_PATH in your project, then .gcda and .gcno files are created in the directory with executable, so you may compute this directory with $<TARGET_FILE_DIR:tgt> generator-expression.
Because you know names of source files, you may compute absolute paths of all gcov-related files, and generate appropriate copiing commands without find.
Another approach could be writting xargs-like program/script by yourself, shipping it with your project, and using it in COMMAND. So
... but I'd rather solve this within CMake instead of having to instruct all the developers to install different tools.
wouldn't be a problem.

Running a bash command via CMake

I'm trying to have CMake either run three bash commands or a bash script. However, I can't seem to get it to work.
The bash commands are:
cd ${CMAKE_SOURCE_DIR}/dependencies/library
make
cd ${CMAKE_BINARY_DIR}
Essentially, I would like CMake to build the library in that directory if it does not already exist.
Here's the CMake code I tried:
if(NOT "${CMAKE_SOURCE_DIR}/dependencies/library/lib.o")
execute_process(COMMAND cd ${CMAKE_SOURCE_DIR}/dependencies/library)
execute_process(COMMAND make)
execute_process(COMMAND cd ${CMAKE_BINARY_DIR})
endif(NOT "${CMAKE_SOURCE_DIR}/dependencies/library/lib.o")
However, it's not building anything. What am I doing wrong?
Also, while I'm here asking this: should the third command, to move to the binary folder, be included?
Thanks!
execute_process() is executed during configure time. But you want this to run at build time, thus add_custom_command() and add_custom_target() is what you're looking for.
In this special case you want to generate an output file, so you should go for add_custom_command() (both are essentially the same, but command produces one or multiple output files, while target does not.
The cmake snippet for this should look something like the following:
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/dependencies/library/lib.o
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/dependencies/library
COMMAND make
)
You then have to add the output file in another target as dependency, and everything should (hopefully) work as expected.
You can also add DEPENDS statements to the add_custom_command() call to rebuild the object file in case some input sources have changed.

what is the difference between 'make after make clean' and just 'make'?

there are C files in a directory and I have a makefile.
I usually use makefile to compile.
I have been wandering the role of the 'make clean'
'make clean' is just to remove files.
Though I didn't use 'make clean', t
he error and warning was shown up when there were something wrong.
I cannot realize why I need to use 'make clean' whenever I change the source file.
make is a utility is to determine automatically which pieces of a large program need to be recompiled, and issue the commands to recompile them.
To prepare to use make, you must write a file called the makefile that describes the relationships among files in your program, and the states the commands for updating each file.
Once a suitable makefile exists, each time you change some source files, this simple shell command:
make
suffices to perform all necessary recompilations. The make program uses the makefile data base and the last-modification times of the files to decide which of the files need to be updated.
We generally use make clean as a generic way to tell clean up the code.ie; remove all the compiled object files from the source code. You can name it as anything you like.
It's convention only. The convention is that clean will return you to a state where all you have is the "source" files. In other words, it gets rid of everything that can be built from something else (objects, executables, listings and so on).
So make clean ; make is expected to build everything from scratch. And, in fact, you'll often find a rule like:
rebuild: clean all
which will do both steps for you.
You should never have to do a clean unless you're wanting to (for example) copy just the source files somewhere. If you have to do so after editing a file, then your Makefile is not set up correctly.
And, if you make and get an error, you should get exactly the same error if you subsequently make without fixing said error.

How to have make build from one directory if the source file exists, otherwise build from another?

I'm working on modifying a huge recursive makefile project that has 6000+ source files. All of which are clearcase controlled. Since I don't want to copy the whole source tree, I'm trying to create a new project only containing the modified source files and thus pull the source from the original tree if they don't exist in my modified tree.
I have already modified the makefile in ModDir to check if each folder exists locally and execute make in that folder if it does. Otherwise it executes make in the sourceDir. My issue lies in the subdir makefiles.
Each subdir makefile contains a list of all of the source files needed for that module. I need to find a way to build the file locally if it exists, else build the file from SourceDir/subdir.
I.e. in my image, the Dir1 makefile needs to build F1 from ModDir/Dir1/F1, and build the other files from SourceDir/Dir1/F2-F3.
I tried to use VPATH to tell make to locate the source files in both locations (ModDir first of course) which works beautifully. However, since make assumes the object files are in the ModDir, it can't find any of the object files built in SourceDir.
I also tried making a pre-build rule to modify the make file list with bash, but I don't know if that's even possible.
How do I use make to build from one directory if the source file exists (ModDir), otherwise build from another (SourceDir)?
The easiest way will be to put your "if ... then ... else" logic in an external bash or batch (whichever OS you use) script and swap makefiles before calling make

Resources