How to execute CMake custom command without building any target? - c++

I have a CMakeLists.txt file with add_custom_command that adds a command to unite all the project source files and generate one output unit.cc file. Is there a way to just run this command without building any target that depends on it? Like cmake -E ... does. I need to sloc the file and don't wanna wait the long compilation.
I tried to look at the docs but they said, IIUC, that I can run commands only when they depend on some target.

Related

Merging make and cmake's make into build system

I have to merge cmake's makes and makes in our build systems. The build systems are supposed to be able to work with both options make and cmake. The problem is that cmake's make exports do not contain all variables and settings, which need to be set as make in our build systems. Basically, we use three complicated build systems for cross platform development and I do not like setting everything on many places, because then it is hard to maintain the system like that.
E g. makefiles from many coders in all build system contains include common file like:
include $(PROJECT_CONF_DIR)/common/something.mk
How to solute it by cmake? I do not like modifying coders' CMakeLists.txt (max. one row solution for them) and I also do not like modifying cmake exports into make files.
Basically, I need to put somewhere in cmake command or cmake's export (the best) some link which will lead to include all 'garbage' expecting by our build tool chains.
Make sure that CMakeLists.txt can contain many cmake subprojects and libraries.
e.g. Our build system from makefiles contains something like:
directories-default:
mkdir -p $(BUILD_DIR)
mkdir -p $(OBJ_DIR)
I need to implement it somehow in cmake include.
To be able to run make directories-default after configuration, you have to create a target. You can make a target that will call a custom command, which would run the shell commands you need.
add_custom_target(directories-default COMMAND mkdir -p "dir1" COMMAND mkdir -p "dir2")
The syntax above will result in a target that is always considered out of date, ie every time you run make directories-default (or make all), the commands will be executed. If you don't want to re-run the command every time you can use a custom command:
add_custom_command(OUTPUT "dir3" "dir4" COMMAND mkdir -p "dir3" COMMAND mkdir -p "dir4")
add_custom_target(directories-default2 DEPENDS "dir3" "dir4")
Here make directories-default2 will only run the commands the first time you run it. You can also create a dependency chain of commands using the DEPENDS argument in add_custom_command.

Can I manually use CMake's cpp file dependency-scanner in my cmake code?

I am trying to add a custom target with CMake that executes one command for each given .cpp file. The command should only be re-executed when the source file itself or one of the included source files changes. AFAIK to achieve this I need a list of all the included files and add them to the DEPENDS option of the add_custom_command() calls that belong to my custom target.
So is there a built-in way to get that list of included files?
I know about the IMPLICIT_DEPENDS option of the add_custom_command() function but it only works for Makefile generators. I would like to make this work for all generators.
Thank you for your time
Edit:
As requested I will post some cmake code to show what I want to achieve.
I want to add a custom target, that runs clang-tidy on all the given .cpp files. When incrementally building the custom target the clang-tidy commands should be re-run whenever a .cpp file or one of its directly or indirectly included header files is changed. Just like re-runs of the compiler are handled.
# ----------------------------------------------------------------------------------------
# mainTargetName The name of the target that shall be analyzed
# files A list of all the main targets .cpp files
#
function( addStaticAnalysisTarget mainTargetName files )
set(targetName runStaticAnalysis_${mainTargetName})
set(command "clang-tidy-4.0 -checks=* -p ${CMAKE_BINARY_DIR}")
foreach( file ${files} )
get_filename_component( baseName ${file} NAME_WE)
set(stampFile ${CMAKE_CURRENT_BINARY_DIR}/analyze_${baseName}.stamp )
set(fullFile ${CMAKE_CURRENT_SOURCE_DIR}/${file})
set(commandWithFile "${command} ${fullFile}")
separate_arguments_for_platform( commandList ${commandWithFile})
add_custom_command(
OUTPUT ${stampFile}
DEPENDS "${fullFile}"
IMPLICIT_DEPENDS CXX "${fullFile}"
COMMAND ${commandList}
COMMAND cmake -E touch "${stampFile}" # without creating a file as a touch-stone the command will always be re-run.
WORKING_DIRECTORY ${CPPCODEBASE_ROOT_DIR}
COMMENT "${commandWithFile}"
VERBATIM
)
list(APPEND stampFiles ${stampFile})
endforeach()
set_source_files_properties(${stampFiles} PROPERTIES GENERATED TRUE) # make the stamp files known to cmake as generated files.
add_custom_target(
${targetName}
DEPENDS ${stampFiles}
)
endfunction()
The problem with that is, that it does not seem to work. When I change included files clang-tidy is not re-run for the affected files.
I used the "Unix Makefile" generator for this example so it should work at least with make. Any hints why it doesn't?
My hopes where that I could achieve the desired behavior for all generators by somehow getting the file-dependencies at cmake time and then adding them to the ''''DEPENDS'''' list. But the dependency scanning must be done each time the command is run, so it can not be done at cmake time. This means that the scanning must be implemented by cmake which it currently is not.
A guy with similar problems:
https://gitlab.kitware.com/cmake/cmake/issues/16830
Edit 2:
I think the problem that the IMPLICIT_DEPENDS option was not working was because I did not use correct filenames. I changed that in the code snipped, but I have not yet tested if it works in the project.
I think the answer to my question is ...
No, you can not use cmakes dependency scanner in the cmake code.
That makes sense, because this problem can not be solved at cmake time, because the dependencies of a .cpp file may change without cmake being re-run.
The problem must be solved within cmake itself at make time. This is done when using the IMPLICIT_DEPENDS option.
Also, I tried to solve a Problem that I did not really have, because at this point I can only run clang-tidy on linux anyways. However, clang-tidy may become available on windows as well and then I may have the problem again.
To sum the comments up:
Tambre stated that CMake is not a compiler and therefore can not do that.
I think this is wrong. According to this article, CMake can parse cpp include dependencies because make has no such dependency searcher itself. That was news to me, but I mostly live on Windows so I am not that familiar with make. It could also be possible that in the meantime make was extended to do its own dependency searching. Also this explains why the IMPLICIT_DEPENDS option is only available for make.
Florian pointed out that it is not necessary to create an own custom target for running clang-tidy. Instead, one can use the CXX_CLANG_TIDY target property to run clang-tidy for each file after compiling it. This means however, that static-analysis can not be separated from the build which could lead to inacceptable buildtimes.
There is the cmake -E cmake_depends command line, that could be used to retrieve dependencies at cmake time. But as stated above, I erroneously thought that I needed the dependencies at cmake time, while I needed them at runtime.
The IMPLICIT_DEPENDS options did not work because I had an error in my cmake code.

Compile a single file under CMake project?

I'm developing a C++ project which is going to be enclosed on a bigger one.
I've seen that on the bigger project (is a Qt application and it's being generated from qmake) I am able to compile a single file from the linux command line, just entering the relative path to the specific file as an argument to make.
On the other hand, I'm using CMake for my own project. When I modify some code for a compilation unit and I have to modify its header file, I have to wait a long time to compile its dependencies and then its own source file. But there are some situations in which I would prefer to check whether the source code in the *.cc file is compilable without errors.
Is there a way to generate a Makefile from CMake the way qmake does this? Switching to qmake is not an option anymore.
You do not have to add extra custom targets to your CMake scripts, as the Makefiles generated by CMake already contain .o targets for each .cc file. E.g. if you have a source file called mySourceFile.cc, there will be a Makefile in your build directory that defines a target called <Some Path>/mySourceFile.cc.o. If you cd into your build directory, you can use grep or ack-grep to locate the Makefile that defines this target, then cd into that Makefile's directory and build it.
E.g. suppose the command ack-grep mySourceFile.cc.o prints something like:
foo/bar/Makefile
119:x/y/z/mySourceFile.o: x/y/z/mySourceFile.cc.o
123:x/y/z/mySourceFile.cc.o:
124: # recipe for building target
Then you can build mySourceFile.cc.o by doing:
cd foo/bar && make x/y/z/mySourceFile.cc.o
CMake doesn't have a generic built-in way of doing this (it's an open issue), but if you're using the Ninja generator, you can can use a special Ninja syntax for building just the direct outputs of a given source file. For example, to compile just foo.o you would use:
ninja /path/to/foo.cpp^
Not out-of-the box. CMake does not expose those "internal" makefile rules in the main makefile.
You can do this only if you consider what kind of file structure CMake uses internally. You can e.g. for compiling a single .obj files using CMake generated makefiles call
make -f CMakeFiles/myProg.dir/build.make CMakeFiles/myProg.dir/main.cc.obj
when you have something like
cmake_minimum_required(VERSION 3.1)
project(myProg CXX)
file(WRITE "main.cc" "int main()\n{\nreturn 0;\n}")
add_executable(myProg main.cc)
To build src/foo.cpp alone:
cmake --build . --target src/foo.cpp.o
No, CMake does not offer built-in support to compile single files.
You have to add a target for each object file, maybe by a function iterating over all files of a directory.
Others have suggested ways to find the target name (ending in .cpp.o) from the .cpp filename, but if you already know the name of a target that will trigger compilation of the .cpp file and you're using ninja this suggestion should be easier.
First build the target:
ninja TriggersCppCompilationLib
Assuming your file was changed or was not yet built, ninja will print the full target name. When you see the name come up, hit enter so it is not overwritten. Then simply copy the name from the terminal (e.g. using tmux copy mode).

clion run cmake on each build

I am not sure if its possible to do this with clion, I was testing out the program and enjoy using it to write c code because the ctags and etags support is really nice.
I am copying some files over from the cmake source tree to the bin location on each build. While using clion if I update some of the files that I am copying the results aren't updated within clion.
If I instead go back to the terminal and just run the typical cmake steps
cmake ../ && make && bin/./program
that copies the updated files and I am able to see my results.
This is the CMake command that I am using in my build.
FILE(COPY ${CMAKE_CURRENT_SOURCE_DIR}/resources/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/bin/resources/)
I might be able to restructure the cmake command to make it copy every time or it might just be a clion issue. I am unsure and would like to be able to take care of this all from within clion, instead of going back to the terminal to run the cmake command for updates to take effect.
If you want CMake to make some action whenever some file is changed, you should create a rule using add_custom_command and pass file via DEPENDS argument. Note, that only file-level dependencies are supported by CMake, for make dependency on directory you need to list all files in it.
# Collect list of files within directory.
FILES(GLOB files_list RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/resources/
"${CMAKE_CURRENT_SOURCE_DIR}/resources/*")
# This will contain full paths to files in binary directory.
set(binary_files_list)
foreach(file ${files_list})
set(source_file ${CMAKE_CURRENT_SOURCE_DIR}/resources/${file})
set(binary_file ${CMAKE_CURRENT_BINARY_DIR}/bin/resources/${file})
add_custom_command(OUTPUT ${binary_file}
COMMAND cmake -E ${source_file} ${binary_file}
DEPENDS ${source_file})
list(APPEND binary_files_list ${binary_file})
endforeach()
add_custom_target(resources DEPENDS ${binary_files_list})
Note, that in case of adding/removing files you should to run cmake explicitely. That's why hardcoded files list is preferred to GLOBing.

CMAKE: performing a file copy AFTER a custom command has run

I have a build script fragment that looks as follows:
foreach(...)
...
add_custom_command( OUTPUT ${fn_c} ${fn_s} ${fn_p_c} {fn_p_h}
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --proto_path=${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${proto_var} --cpp_out=. --plugin=protoc-gen-RBLRPC=${CMAKE_BINARY_DIR}/tools/protoc-gen-RBLRPC --RBLRPC_out=.
DEPENDS ${proto_var}
)
if(${M_S_} OR ${M_C_})
set(MARSHALL_RPC_FILES ${MARSHALL_RPC_FILES} ${fn_p_c})
message(status "copy marshall -------------------")
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/${fn_c}
${CMAKE_CURRENT_BINARY_DIR}/${fn_s}
${CMAKE_CURRENT_BINARY_DIR}/${fn_p_h} DESTINATION ${CMAKE_SOURCE_DIR}/include/rpc/marshall)
endif()
...
endforeach(...)
The copied files are not generated untill the custom comand is executed, however cmake attempts to copy the files upon first pass over the script. I'd welcome any suggestions to solve this problem , without drastically changing my scrips.
Don't use file(COPY...) function, but add the following command to your add_custom_command:
COMMAND ${CMAKE_COMMAND} copy ${CMAKE_CURRENT_BINARY_DIR}/${fn_c}
${CMAKE_SOURCE_DIR}/include/rpc/marshall
But for what you're going to do, I would suggest you keep your source tree clean, add directly use the generated files from the build directory. That would break, for instance, if you want to make two different build tree from a single source tree.
edit :
CMAKE_COMMAND is documented in the variable section of the online man-page documentation, (search for CMAKE_COMMAND and not ${CMAKE_COMMAND}.
On the command line CMAKE -E will show you a list of portable commands useable.