Lowering cmake intelligence - Page 1
Forum section: electronics / general

author: PlainName
author_rank: Super Contributor
timestamp: December 13, 2020, 08:34:56 am
content: I need to run a system command from cmake. It's just a version checker that updates (if necessary) version.h. I can get it to run and, using add_custom_target(... ALL ...) I can even get it to run every build time. What I haven't managed is to get it to runfirstso it can update version.h and then have that compiled into the app - the damn thing always runs after everything else is compiled.Anyoneau faitenough with cmake to know how to get some system command to run every build before anything else happens?

author: gmb42
author_rank: Frequent Contributor
timestamp: December 13, 2020, 07:58:34 pm
content: The target that creates version.h should be added as a dependency to the target that uses version.h:add_dependencies(codeTarget versionHeaderTarget)

author: PlainName
author_rank: Super Contributor
timestamp: December 14, 2020, 12:55:58 am
content: Thanks - I'll play with than and report back

author: PlainName
author_rank: Super Contributor
timestamp: December 14, 2020, 04:06:35 am
content: Hmm. Well, I don't get anywhere with this.The situation is that this is to be part of the ESP32 build, so the cmake setup is largely out of my hands. OK, that's not strictly true since I could override a lot and even take it over completely, but the aim is to have minimal change to the standard idf.py command.So, I don't know what codeTarget is. Thinking about it, and having had this work once just by including version.h in the appropriate .c, would this actually fix the problem? It seems to be that I would just be telling the system that something depends on version.h, and that I will build version.h every time. However, after the first run, version.h will exist and will be unchanged, so whatever depends on it won't be compiled, andthenmy custom command gets run.That's what I've see happen : first run, my pre-build.bat gets run, the version.h change triggers a build of the dependant source, modules linked, everything is fine. Second run, dependency check figures nothing to do, pre-build.bat gets run, everything is linked.

author: gmb42
author_rank: Frequent Contributor
timestamp: December 14, 2020, 10:31:16 am
content: This is the fundamentals of CMake, the language describes "targets" that are some artefact, (e.g. an executable, a library or even a header file), the method to use to "make" the target, the inputs to the target (e.g. sources) and the dependencies of the target (e.g. libraries to be built before the executable).You should have a target that describes the header file to be produced (in my example versionHeaderTarget) and a target that describes the code that consumes that header file (named codeTarget in my example).As CMake produces a file that is use by the build system (make, or ninja or Visual Studio or whatever) the build system will always rebuild when the implicit dependencies require it (e.g. version.h changes), but the build system won't necessarily modify version.h unless the CMake instructions cause it to be modified, e.g. because it depends on something else or is permanently "unsatisfied" so is modified every build.Google "CMake generate version header" to see some examples if all you want to do is cut and paste, e.g.this SO answer.

author: PlainName
author_rank: Super Contributor
timestamp: December 14, 2020, 12:19:42 pm
content: Thanks. I am slowly getting my head around this.Maybe

author: radiogeek381
author_rank: Regular Contributor
timestamp: December 14, 2020, 03:59:46 pm
content: Are you sure that one of your source files is actually consuming "version.h" ??This is all that I need to do to make sure version.h gets generated at the "right time"Code:CONFIGURE_FILE ("${PROJECT_SOURCE_DIR}/version.h.in""${PROJECT_BINARY_DIR}/version.h")INCLUDE_DIRECTORIES("${PROJECT_BINARY_DIR}")INSTALL(FILES ${PROJECT_BINARY_DIR}/version.h DESTINATION "include/SoDaRadio")And then somewhere in the sources I have :Code:src/UI.cxx:#include "version.h"

author: PlainName
author_rank: Super Contributor
timestamp: December 15, 2020, 01:27:58 am
content: Yep. One file has '#include version.h' and that works. Once.On the first build after putting that in, it works perfectly - pre-build.bat gets run and then the right file gets compiled and the project linked.Second run, since version.h hasn't changed, compile check runs (nothing gets compiled), then pre-build.bat gets run and the project linked. If version.h is indeed changed then it will take another run to notice that and get it compiled in.Of course, I could run the make from a script that runs pre-build first, and I am sorely tempted

author: gmb42
author_rank: Frequent Contributor
timestamp: December 16, 2020, 10:48:15 am
content: This is why you need to add a dependency on the target that runs pre-build.bat to the target that builds the program output.

author: PlainName
author_rank: Super Contributor
timestamp: December 17, 2020, 04:40:06 am
content: Trouble with add_dependencies() is that it wants a top-level logical target (created by add_executable, add_library, or add_custom_target) which I don't have. Currently, a change in version.h is picked up and causes a compile, which sounds to me like the dependency is working fine. To add something, add_dependencies() would need to change the order in which the dependency check is done. I think the problem is that the pre-build custom command is run after everything else is done, so any change in version.h isn't picked up.

author: gmb42
author_rank: Frequent Contributor
timestamp: December 17, 2020, 04:05:05 pm
content: The extra dependency is required to force the target that modifies version.h to be run before the target that consumes it.Obviously (I hope) any change in version.h will cause any consumer of it to be rebuilt (and .h dependencies do NOT need to be specified in the CMake rules) but what you need is dependency ordering to ensure the target that modifies version.h is run first.Why isn't the process that modifies version.h in an add_custom_target() block? The SO example I linked to earlier does exactly that.

author: PlainName
author_rank: Super Contributor
timestamp: December 17, 2020, 05:26:01 pm
content: QuoteYes, that's the sticky bit right now.QuoteIt is!Code:add_custom_target(svn_version ALL)ADD_CUSTOM_COMMAND(TARGET svn_versionCOMMAND pre-build.batWORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")I put a DEPENDS in there earlier, but it was just replicating what the '#include version.h' was doing.