Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 512
mloskot Avatar asked Jul 08 '12 12:07

mloskot


2 Answers

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

like image 157
mloskot Avatar answered Nov 01 '22 08:11

mloskot


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.

like image 21
arrowd Avatar answered Nov 01 '22 09:11

arrowd