Author Topic: Lowering cmake intelligence  (Read 2035 times)

0 Members and 1 Guest are viewing this topic.

Online PlainNameTopic starter

  • Super Contributor
  • ***
  • Posts: 7293
  • Country: va
Lowering cmake intelligence
« on: December 13, 2020, 08:34:56 am »
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 run first so it can update version.h and then have that compiled into the app - the damn thing always runs after everything else is compiled.

Anyone au fait enough with cmake to know how to get some system command to run every build before anything else happens?
 

Offline gmb42

  • Frequent Contributor
  • **
  • Posts: 302
  • Country: gb
Re: Lowering cmake intelligence
« Reply #1 on: December 13, 2020, 07:58:34 pm »
The target that creates version.h should be added as a dependency to the target that uses version.h:

add_dependencies(codeTarget versionHeaderTarget)
 

Online PlainNameTopic starter

  • Super Contributor
  • ***
  • Posts: 7293
  • Country: va
Re: Lowering cmake intelligence
« Reply #2 on: December 14, 2020, 12:55:58 am »
Thanks - I'll play with than and report back :)
 

Online PlainNameTopic starter

  • Super Contributor
  • ***
  • Posts: 7293
  • Country: va
Re: Lowering cmake intelligence
« Reply #3 on: December 14, 2020, 04:06:35 am »
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, and then my 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.
 

Offline gmb42

  • Frequent Contributor
  • **
  • Posts: 302
  • Country: gb
Re: Lowering cmake intelligence
« Reply #4 on: December 14, 2020, 10:31:16 am »
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.
 

Online PlainNameTopic starter

  • Super Contributor
  • ***
  • Posts: 7293
  • Country: va
Re: Lowering cmake intelligence
« Reply #5 on: December 14, 2020, 12:19:42 pm »
Thanks. I am slowly getting my head around this.

Maybe :)
 

Offline radiogeek381

  • Regular Contributor
  • *
  • Posts: 125
  • Country: us
    • SoDaRadio
Re: Lowering cmake intelligence
« Reply #6 on: December 14, 2020, 03:59:46 pm »
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: [Select]
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: [Select]
src/UI.cxx:#include "version.h"
 

Online PlainNameTopic starter

  • Super Contributor
  • ***
  • Posts: 7293
  • Country: va
Re: Lowering cmake intelligence
« Reply #7 on: December 15, 2020, 01:27:58 am »
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 :)
« Last Edit: December 15, 2020, 01:30:23 am by dunkemhigh »
 

Offline gmb42

  • Frequent Contributor
  • **
  • Posts: 302
  • Country: gb
Re: Lowering cmake intelligence
« Reply #8 on: December 16, 2020, 10:48:15 am »
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.
 

Online PlainNameTopic starter

  • Super Contributor
  • ***
  • Posts: 7293
  • Country: va
Re: Lowering cmake intelligence
« Reply #9 on: December 17, 2020, 04:40:06 am »
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.
 

Offline gmb42

  • Frequent Contributor
  • **
  • Posts: 302
  • Country: gb
Re: Lowering cmake intelligence
« Reply #10 on: December 17, 2020, 04:05:05 pm »
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.
 

Online PlainNameTopic starter

  • Super Contributor
  • ***
  • Posts: 7293
  • Country: va
Re: Lowering cmake intelligence
« Reply #11 on: December 17, 2020, 05:26:01 pm »
Quote
what you need is dependency ordering to ensure the target that modifies version.h is run first

Yes, that's the sticky bit right now.

Quote
Why isn't the process that modifies version.h in an add_custom_target() block?

It is!

Code: [Select]
add_custom_target(svn_version ALL)


ADD_CUSTOM_COMMAND(TARGET svn_version
COMMAND pre-build.bat
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")

I put a DEPENDS in there earlier, but it was just replicating what the '#include version.h' was doing.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf