Adding a library with CMake with generated source files - cmake

tl;dr;
When using ADD_LIBRARY in CMake it will check during cmake .. that all the source files exist. I have some that are generated during compile time. Is there a way to force CMake to ignore the missing files since they will exist when they are needed?
Full version:
I am trying to build Sqlite3 with CMake, and I can get it to compile, however, I need to comment out a few lines in CMake and run it, then uncomment them and run it again. I would like to do everything in one pass.
The main issue I'm having is that Sqlite3 using a code generator called "lemon". So to properly build everything, I need to compile lemon. Then I need to run lemon. Once lemon is done running there is a new file called "parse.c". "parse.c" needs to be included with the source to build sqlite3.
I will strip down the code to show the applicable bits.
set(SourceFiles
#Lots of Files are here
build/parse.c
)
add_executable(lemon sqlite/tool/lemon.c)
add_custom_target(CreateParse ALL COMMAND
cp ../sqlite/tool/lempar.c .
&& ./lemon -s ../sqlite/src/parse.y
&& mv ../sqlite/src/parse.h .
&& mv ../sqlite/src/parse.c .
&& mv ../sqlite/src/parse.out .)
add_library(sqlite ${SourceFiles})
add_dependencies(CreateParse lemon)
add_dependencies(sqlite CreateParse)
So there are 3 steps that happen here:
The executable lemon is created.
lemon is used to create parse.c (among other things)
parse.c is compiled with a ton of other files to create the sqlite3 library.
With the add_dependencies this should work. But it doesn't. The reason it doesn't work is that build/parse.c doesn't exist on the first pass. I've been able to work around it by commenting out parse.c. After it is done half building. Then I can uncomment it and it will compile successfully.
I've looked into using ADD_CUSTOM_COMMAND, which I believe will run lemon when cmake .. is run rather than ninja is run. However, when cmake .. is run, "lemon" doesn't exist yet so the custom command is unable to run.
Edit 1
So I came up with a hack...
execute_process(COMMAND touch ${CMAKE_SOURCE_DIR}/build/parse.c)
So when cmake .. is run it will create an empty file in the correct spot. However, there has to a be a better way. Help is appreciated.

Related

Cause CMake to force recompile a file, but only if project is otherwise recompiled?

I have generally the same question as in Can CMake always force the compilation/build of a specific file?
I have a C++ file using __DATE__ to display the build date of my app. But if this file is not modified, it will not be rebuilt and the date will not be updated.
Can CMake always rebuild that specific file?
... except I want something slightly different:
In the CMake project I have (for C, transpiles to Makefile which I use), sometimes there are no actual changes to the code when I run make, which is detected nicely, in the sense that there is no recompilation (or relinking) of the program.
Obviously, in this case, I do not want to update the timestamp, and end up with a new executable, which is otherwise identical to the previous one - apart from the build date.
I have seen in the quoted post, that one simply has to ensure a changed timestamp on the file, to force a recompilation. So, assuming my __DATE__ usage is in use_date.c, what I'd want, is that the timestamp of use_date.c is updated (forcing recompilation), only if any other file in the project (say, main.c) has been changed, so it forces project recompilation and linking (obviously, this should also work if I just change use_date.c manually, and no other file).
So, assuming my project just generates an executable (no libraries):
add_executable(my_project use_date.c other_file.c main.c)
... is it possible to add a CMake step, that updates the timestamp of use_date.c (and thus causes its recompilation), only if otherwise the project is getting recompiled and relinked?
OK, found a way: it seems kind of a squeaky solution - hopefully someone more knowledgeable in CMake will post a proper solution eventually. But in the meantime:
I've found that add_custom_command with POST_BUILD runs the custom command only if a new binary (.elf for me) is generate, and otherwise does not run the custom command.
So, basically, we could have a small bash script in the custom command:
If this bash script is called, we can assume that POST_BUILD has called it, meaning that a new .elf (for whatever other reasons) has been built
So we can touch the use_date.c, and while in the bash script still, descend into the build directory, and explicitly run make again - which should recompile only use_date.c, and then link with the rest from the previous build.
This essentially works - except, it causes an infinite loop.
This can get solved with creating a temp file:
If this bash script is called, we can assume that POST_BUILD has called it, meaning that a new .elf (for whatever other reasons) has been built
check for a temp file:
if it does not exist, create it - and then we can touch the use_date.c, and while in the bash script still, descend into the build directory, and explicitly run make again - which should ...
if it does exist, then we've been called from the second .elf. build (for the touched use_date.c), so we want to remove the temp file, and just exit - stopping the infinite loop
This seems to work fine:
add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD
DEPENDS ALL
#COMMAND bash ARGS -c "touch ${CMAKE_CURRENT_SOURCE_DIR}/use_date.c && cd build && make" ## infinite loop!
COMMAND bash ARGS -c "if [ ! -f .refresh ]; then echo '.refresh' | tee .refresh && touch ${CMAKE_CURRENT_SOURCE_DIR}/use_date.c && cd build && make; else rm -v .refresh; fi" # OK!
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "remake with refreshed __DATE__ in use_date.c (${CMAKE_CURRENT_SOURCE_DIR})"
VERBATIM
)

how to use clang tidy in CMake

I would like to use CMake and clang-tidy in my project, however I see that build times are quite a bit higher when I use this in all the main cmake file:
set(CMAKE_CXX_CLANG_TIDY
clang-tidy-11;
-format-style='file';
-header-filter=${CMAKE_CURRENT_SOURCE_DIR};
)
It is working well, but I don't want to have this build-time penalty every time I build the project during development. Therefore I thought I would make a separate target that builds all, but uses clang-tidy. And when I do a regular debug or release build it does not do any checking. However I don't know how to do this in Cmake. Do I make a custom target with a command "cmake --build" with a target_set_property of CMAKE_CXX_CLANG_TIDY?
This feels rather clunky, so my question is, are there other ways to do this?
however I see that build times are quite a bit higher when I use this in all the main cmake file:
You're going to have to pay for the cost of running clang-tidy sometime or another. It's essentially running the first few phases of a compiler to analyze your code and look for errors.
Setting CMAKE_CXX_CLANG_TIDY runs clang-tidy in line with your build, as you have observed.
This feels rather clunky, so my question is, are there other ways to do this?
Yes. When using the Ninja or Makefile generators, you may set -DCMAKE_EXPORT_COMPILE_COMMANDS=ON at the command line. That will create a file called compile_commands.json in your build folder that the standalone clang-tidy can read.
In sum, at the command line, you would manually run:
$ cmake -G Ninja -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
$ clang-tidy-11 -format-style=file -header-filter=. -p build
The -p flag tells clang-tidy in which directory to find your compile_commands.json.

In CMake how do I create a file needed at configure time?

Edit: my question targets the early configure stage where CMake input files are still being parsed and thus have to be present before include() is being called. So the answer found here: Force CMake to generate configure_file target every build does not solve my problem since it generates files after include() statements have been interpreted.
I have a CMakeLists.txt that includes a file which is generated in the configure stage:
execute_process(COMMAND "my-generator -o generated.cmake")
include(generated.cmake)
Apart from the fact that this approach doesn't feel right (not to say elegant) I now need to re-generate that file before every build (my-generator produces output that incorporates the current time).
My assumption is that I can't use add_custom_command() or add_custom_target() because the file would be generated at compile time but needed in the configure-step.
This very old post suggests to touch the input file so I did this:
execute_process(
COMMAND "my-generator -o generated.cmake"
COMMAND cmake -E touch "${CMAKE_CURRENT_LIST_FILE}")
.. which does not produce errors but calling make multiple times won't run the configure step more than once.
What do I do wrong? Is there a better approach?

How to find the CMake command line I used for the build?

This is what typically happens. I get source code that has cmake build scripts. I create a build subdirectory, change to it, run cmake <options> ... Depending upon the project and its dependencies I have to repeat the last step until it finds all necessary dependencies and generates makefiles. I successfully build and use the project. Few days pass, I forget about this installation. Then one day I'm trying to setup the same project on another machine and now I can't recall what exact CMake command line I used in the past to get things working.
I still have the old build directory on the old machine. Can I find the cmake command line I used in the past, by looking into some of the autogenerated files in the build directory? I was expecting CMake would just put the exact command line I used in one of these files in commented form. But if it does so, I haven't found it yet.
How can I find the original CMake command line I used?
You can't.
Original CMake command can be guessed from analysis of CMakeCache.txt
As a workaround, you could always create a simple wrapper to store the original command line used. Something along these lines:
#!/bin/bash
echo "$#" > cmake_command.log
$#

CMake build & link to library without installing to /usr/local or elsewhere

I'm trying to include an external library in a build environment that uses CMake. I'm not trying to install it on the local system (in fact I'd rather not do that, I don't want /usr/local clogged up with all kinds of libraries); I'd just like to have the resulting libxml2.a available for linking with my executable. I can build it fine with the following in CMakeLists.txt:
set (LIBXML_PATH ${MY_SOURCE_DIR}/libxml2-2.9.1)
add_custom_target (build_libxml ALL
COMMENT "Building libxml"
COMMAND ./configure --prefix=/tmp
COMMAND make
WORKING_DIRECTORY ${LIBXML_PATH}
)
But I'm still having trouble with the following:
1) Is this the right approach in the first place, for the general purpose of getting libraries built with configure and make into a CMake environment?
2) How do I get the resulting library (i.e. libxml2.a) under my build output directory?
3) How can I link to that library for my executable builds?
I tried a fiddly solution with
ADD_LIBRARY( xml2 STATIC libxml2.a )
but it seems like there must be a better way than hauling a whole library's contents into… a library.
Thanks.
You need to make it clearer to CMake what is going on here. All it can see now is that you have some custom command that it will run every time. Instead of using add_custom_target with COMMAND, I've found it better to use add_custom_command.
Something like this:
set (LIBXML_PATH ${MY_SOURCE_DIR}/libxml2-2.9.1)
add_custom_command(
OUTPUT libxml2.a
COMMENT "Building libxml"
COMMAND ./configure --prefix=/tmp
COMMAND make
WORKING_DIRECTORY ${LIBXML_PATH}
)
target_link_libraries(your-program libxml2.a)
By doing it this way, CMake can understand that your custom command's essential product is libxml2.a, and when CMake sees something depending on that, it will run the command (if the library doesn't exist already).