mloskot
mloskot

Reputation: 38912

How to configure CMake target or command to preprocess C file?

I originally asked this question on CMake mailing list: How to configure target or command to preprocess C file?

I'm porting build configuration based on GNU Autotools to CMake and I have to deal with C preprocessing to generate a file.

The input for preprocessor is SQL file with C preprocessor directives used, like #include "another.sql", etc.

Currently, Makefile uses the following rule to generate plain SQL file as output:

myfile.sql: myfile.sql.in.c
    cpp -I../common $< | grep -v '^#' > $@

So, the myfile.sql is meant to be one of products of the build process, similar to share libraries or executables.

What CMake tools should I use to achieve the same effect?

It's unclear to me if I should use add_custom_command, add_custom_target or combine both.

Obviously, I'm looking for a portable solution that would work at least with GNU GCC and Visual Studio toolsets. I presume I will have to define platform-specific custom commands, one for cpp preprocessor, one for cl.exe /P.

Or, does CMake provide any kind of abstraction for C preprocessor?

I scanned the archives, but I only found preprocessing of fortran files or solutions based on make capabilities: make myfile.i So, it's not quite what I'm looking for.

UPDATE: Added answer based on solution received from Petr Kmoch on CMake mailing list.

Upvotes: 11

Views: 8240

Answers (2)

arrowd
arrowd

Reputation: 34401

To take advantage of CMake' make myfile.i feature, you can do this:

add_library(sql_cpp_target EXCLUDE_FROM_ALL myfile.sql.in.c)

Now running make myfile.sql.in.c.i will produce preprocessed source for you, using defined CMAKE_C_FLAGS. It might be possible to change output name and dir for preprocessed file.

At any rate, you'd need to wrap these make invocations into add_custom_target(ALL ...) to make CMake run them during build.

Use CMAKE_MAKE_PROGRAM variable in targets definitions.

If you want to abstract from build tool, you can call cmake itself to build a target for you. Use ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target targetname when defining custom target.


Alternatively, you can just add_custom_command() which runs specified compiler to preprocess files and put them at the appropriate place. But this seems to be less flexible, IMO.

Upvotes: 6

mloskot
mloskot

Reputation: 38912

I'm answering the question to myself by copying essential parts of solution received from Petr Kmoch as response to my post in the mailing list.

First, create a custom command using add_custom_command (version with the OUTPUT signature) to actually do the preprocessing.

For example:

add_custom_command(
  OUTPUT myfile.sql
  COMMAND "${CMAKE_C_COMPILER}" -E myfile.sql.in -I ../common
  MAIN_DEPENDENCY myfile.sql.in
  COMMENT "Preprocessing myfile.sql.in"
  VERBATIM)

Second, configure the command trigger:

  • If the command output file (myfile.sql) is used in another target, added as a source file added to add_library or add_executable, it is enough to specify it in these commands. CMake will find it as a dependency and run the custom command as required.

  • If the command output file is a final output not used as dependency in any other targets, then add a custom target to drive the command using add_custom_target

For example:

add_custom_target(
  ProcessSQL ALL
  DEPENDS myfile.sql
  COMMENT "Preprocessing SQL files"
  VERBATIM)

Credits: Petr Kmoch

Upvotes: 9

Related Questions