Running a bash command via CMake - bash

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.

Related

Set workdir/pwd of go build

Is it possible to set the workdir to a different path?
For example, I want to run go build from the root path, but my source code is under a different directory, and I do not want to cd to it.
npm, for example, has the --prefix, which serves for this purpose.
Yes, its possible.
go build -o [output file path/name] [source code file path/name]
For example, if your source code file is located in projectdir/code/src/ and want to build and save output to projectdir/code/out, do following:
$ go build -o projectdir/code/out/main projectdir/code/src/main.go
As per go build documentation:
If the named output is an existing directory or ends with a slash or
backslash, then any resulting executables will be written to that
directory.
So our above build command can be rewritten like this:
go build -o projectdir/code/out/ projectdir/code/src/main.go
and it will generate executable named main in projectdir/code/out/ directory.
For more details, run go help build
No, this is not possible with 1.19. Just cd into it.
Go 1.20 (yet unreleased) brings the -C flag which might be what you want.

How to use GNU Makes dry run mode with CMake generated Makefile before actually performing the installation

Every now and then a new tarball or a new xyHub/Lab-repository needs to be built. They usually come with a Makfile or an Autotools/CMake/XY-Generator provides one on the fly. As the maintainers most likely use another operating system or distribution than the one I am currently running, the assumptions that went into their Makefiles usually do not fit my filesystem hierarchy (lib vs. lib64, bin vs. sbin, /usr/lib vs. /lib and so on). As the final command in the build sequence usually is
sudo make install
it is quite annoying to move thousands of files to the correct place. Or even worse determine which files of my distribution were overwritten. Here GNU Makes dry run mode comes in very handy. Running
sudo make -n install
first, saves me the trouble of cleaning up my file system, by just printing all the commands from all active GNU Make recepies without executing them. In case of a handwritten or Autotools-generated Makfile this works as intended. If the Makefile contains something like:
#PREFIX is environment variable, but if it is not set, then set default value
ifeq ($(PREFIX),)
PREFIX := /usr/local
endif
install: unixlib.a
install -d $(DESTDIR)$(PREFIX)/lib/
install -m 644 unixlib.a $(DESTDIR)$(PREFIX)/lib/
install -d $(DESTDIR)$(PREFIX)/include/
install -m 644 unixlib.h $(DESTDIR)$(PREFIX)/include/
I would see exactly what would happen. Every install/cp/mv-command with the full path information would be printed. If I made a mistake with the install prefix in the configure step I can see it there. If the default in the Makefile is weird because it comes from another OS, I would see it there.
Now in case of a CMake-generated Makefile this is different. Doing
mkdir build && cd build
cmake ..
make
sudo make -n install
only produces output that ends in
...
make -f CMakeFiles/Makefile2 preinstall
/usr/bin/cmake -E cmake_echo_color --switch= --cyan "Install the project..."
/usr/bin/cmake -P cmake_install.cmake
As these commands get not executed, just printed, I do not get all the cp/mv/mkdir/install/etc-commands that I would like to see first, before I let the Makefile touch the file system.
Is there a way to get the list of commands that would be executed from the install target in a CMake-generated Makefile as it is the case with handwritten or Autotools-generated ones?
Is there a way to get the list of commands that would be executed from the install target.
Actually, the core part of installation process is contained in the file cmake_install.cmake (which is created in the build directory). This file is processed as CMake script using cmake -P flow of the cmake executable.
The script cmake_install.cmake performes installation of files with install command. Semantic of the install command, used by the script, differs from the one described in documentation: internally, CMake uses some undocumented features of the command.
But it shouldn't be so hard to understand cmake_install.cmake script in general and deduce paths from it.

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.

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.

Resources