0

I have custom source files that are not C/C++. These files are compiled to C source files and then those C files are compiled by cmake as usual.

However, my custom files can have dependencies that can change during development.

For example let us say the I have the files source1.lang, source2.lang, source3.lang...

source1.lang

... some code

source2.lang

import source1;
... some code

I compile these files as

./langc source1.lang
./langc source2.lang
...

and I get source1.c, source2.c ...

Now, as you can see source2.lang depends on source1.lang. I can find these dependencies for these custom files at any time by pre-processing them. And then generate an explicit dependency of source2.lang on source1.lang so that it gets recompiled if source1.lang is modified.

Right now, I have a custom command like this

# This is populated automatically.
set(SOURCE2_DEPENDS source2.lang source1.lang) 

add_custom_command(
        DEPENDS ${SOURCE2_DEPENDS }
        COMMAND ./langc source2.lang
        OUTPUT source2.c 
        COMMENT "Compiling source2.c"
     )

The problem is the dependencies can change during development. That is, SOURCE1_DEPENDS can change after configuration. For example I can modify source2.lang to import source3.lang

source2.lang

import source1;
import source3;
... some code

I can now see that source2.lang is modified. So I pre-process it to find the new dependencies. But how do I let cmake know that the dependency has changed?

The only way I can see so far is for Makefile generators to modify the generated build.make file to add and remove these dependencies manually.

However, how I can I tell cmake in a generic way that these are the new dependencies? Basically as cmake does normally when you add a new #include to a C source file. So that things work for other generators as well.

1 Answer 1

4

The following I think only works as of now with Ninja generator. I think it also works with makefile generator, but I didn't check.

The add_custom_command has DEPFILE option. You have to generate a depfile in makefile-ish style from your command. For example:

add_custom_command(
        DEPENDS ${SOURCE2_DEPENDS}
        DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/source2.d
        COMMAND ./langc 
               --depfile ${CMAKE_CURRENT_BINARY_DIR}/source2.d
               --depfile-relative ${CMAKE_BINARY_DIR}
                source2.lang
        OUTPUT source2.c 
        COMMENT "Compiling source2.c"
     )

The generated depfile should look like a makefile dependency file generated by gcc with the standard -MT/-MD options. Note the target path has to be relative to ${CMAKE_BINARY_DIR}. So langc program should generate the following file in ${CMAKE_CURRENT_BINARY_DIR}/source2.d:

buildir/subdir/source2.c: /absolute/path/to/be/safe/source2.lang /absolute/path/to/be/safe/source1.lang /etc..
# ^^ must be relative to CMAKE_BINARY_DIR

Cmake inserts depfile commands into generated ninja build system and they get picked by ninja and the generator then knows the depedency. But then, you could think about adding your own language to cmake so that *.lang files are picked automatically by cmake.

I did the DEPFILE generation on a project that I used m4 to preprocess source files. With --debug=p m4 option the preprocessor printed m4debug: including file <the file> or something like that while preprocessing the file. From those messages I extracted files and generated the dependency file. The code is available here m4.cmake and m4.sh.

Sign up to request clarification or add additional context in comments.

8 Comments

This is basically what I had in mind to do for Makefile generators. Basically manually inserting those A:B dependency rules to the end of the build.make file generated by cmake.
"But then, you could think about adding your own language to cmake so that *.lang files are picked automatically by cmake" How do I do that? That was something I was hoping would be possible.
I have never did it, so I have no experience. There is a stackoverflow thread somewhere that explains how to do it.
I have looked for something like that over on the cmake documentation and on stackoverflow. No Luck. Can you please try to remember the thread if you can? It might help.
stackoverflow.com/questions/38293535/… The example there is a pearl. I think also inspecting existing files, like CMakeDetermineCCompiler CMakeCCompiler.cmake.in etc. in cmake/Modules will help.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.