CMake build issues

I am trying to use CMake to create a custom project that includes using emscripten to provide javascript binding for my C ++ library.

This is what I want my CMakeLists.txt file to reach

  • Specify source locations for my files (DONE)

  • Configure the appropriate COMPILERS to use, as well as compiler flags, etc. (DONE)

  • Use custom build to generate new cpp files (detailed steps below)

    • use your own tool (python script) to create interface/glue.cpp

    • Create a new EMPTY file interface/glue_wrapper.cpp

    • For each header file f

      in ${my_header_files}

      add #include "f"

      to fileinterface/glue_wrapper.cpp

    • The final entry in interface/glue_wrapper.cpp

      must be#include "glue.cpp"

  • Use your own assembly to generate my javascript file with the following logic:

    • create a variable $ {ALL_SOURCES} containing all the sources listed above in step 1 and interface/glue_wrapper.cpp

      step 3 above
    • compile a COMMAND command that evaluates: ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js

I've spent the last 7 hours on steps 3 and 4 - no success.

This is what I have so far (regarding steps 3 and 4 above)

# Build Interface
ADD_CUSTOM_COMMAND(
                OUTPUT interface/glue.cpp
                COMMAND cd interface
                COMMAND python ${PLATFORM_PREFIX}/tools/webidl_binder.py ${myclasses_INTERFACE} glue
                # Need to loop through list and generate include statements ...
                #COMMAND echo "#include <glue.cpp>" > glue_wrapper.cpp
                 )

# Build JS library
ADD_CUSTOM_COMMAND(
                OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js
                COMMAND ${CMAKE_CXX_COMPILER} # Nothing seems to work anyway .... giving up finally :(
                )

      

I am using cmake 3.2.1 and am building on Ubuntu 14.0.4. I am trying to create Unix MakeFiles.

My question is:

How can I modify the code snippet above to implement the required functionality as specified in steps 3 and 4?

+3


source to share


1 answer


It looks like the content glue_wrapper.cpp

does not depend on build time values ​​at all, they are based solely on information available in CMake time (variable content my_header_files

). Therefore, you can create a file in CMake with a simple command file()

:

file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp)  # erase file if it exists
foreach(header IN LISTS my_header_files ITEMS glue.cpp)
  file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp "#include \"${header}\"\n")
endforeach()

      

A custom command to create a .js library should work fine:

add_custom_command(
  OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js
  COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js
  DEPENDS ${ALL_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp
  COMMENT "Building ${PROJECT}.js"
  VERBATIM
)

      

Like any custom CMake command, it will only be included in the build if anything depends on its output (I suspect this is why your approach didn't work). Therefore, you must add a custom target for command management:

add_custom_target(
  JsLibrary ALL
  DEPENDS ${PROJECT_JS_DIR}/${PROJECT}.js
  COMMENT "Building JsLibrary"
)

      

This should be all that is needed.

As a side note, note that it add_custom_command

has an argument WORKING_DIRECTORY

that you should use instead COMMAND cd

.


The CMake relationship between custom commands and custom targets can take a while to complete the search, so I'll try to explain what's going on in the code above.

Custom command

The command add_custom_command(OUTPUT x ...)

creates a build rule that produces output. Basically, this is what CMake says:

If anyone needs a file x

, this is how you create it.

The command doesn't add anything to the generated assembly. It only provides CMake information about how the file will be created.

Individual call components:

add_custom_command(
  OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js

      

The file or files created by this custom command. It says "custom command creates these files".

  COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js

      

The parameter COMMAND

enters the command line of the command to be executed. It says, "this is what you have to do to create the files listed in OUTPUT

."

  DEPENDS ${ALL_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp

      

This section DEPENDS

presents the dependencies (prerequisites) of the command. Each item that follows it is one file that is command dependent. It says, "If any of these files are missing or if any of these files are newer than any of the output files, this command should be rerun."



Notice in particular the dependency on ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp

, I will come back to it later.

  COMMENT "Building ${PROJECT}.js"

      

This is purely documentation, it will be printed when the custom command is executed (= built).

  VERBATIM
)

      

This means CMake correctly avoids any special characters in the section COMMAND

for the shell that will execute the command. Basically, always put this in custom commands unless you know for sure that you have a reason not to.

Custom target

As I mentioned above, CMake adds custom commands to the prefab system if something asks for their output. A common target (i.e. a library or executable) can do this by listing the output file among its source files. This is typical in cases where a custom command generates a C ++ source file, for example from an IDL definition.

A custom command can also display the output of another custom command in a section DEPENDS

that creates the required dependency. However, both will only be re-enabled if the output of the "master" command is requested somewhere.

If the generated file is in fact a final product and not just a source file for a normal purpose, an explicit dependency on it must be listed somewhere to make sure it is generated. This is where a custom goal comes in. This is a target (just like an executable or library), so it will always be present in the assembly. When using a makefile-based generator, the custom target is just an extra rule. Analyze the one I put in the answer above:

add_custom_target(
  JsLibrary

      

JsLibrary

is just a symbolic name for a target. It can be whatever you want. This is the name that you type in the command line to create file .js

: > make JsLibrary

.

ALL

      

By default, custom targets are not part of the target all

being called make all

; you need make

them explicitly. Adding the argument all

makes the custom target part make all

, which I assumed you want here.

DEPENDS ${PROJECT_JS_DIR}/${PROJECT}.js

      

This is the key line and the reason why we created a custom goal. This tells CMake that the custom target depends on the generated file. CMake now sees that the file is required by something that is part of the JsLibrary

build system (i.e. Custom command ) and looks to see if it knows how to create such a file. It finds the custom command and makes sure the correct rules are added to the generated assembly.

  COMMENT "Building JsLibrary"
)

      

This is pure documentation again and will show up every time the target is done (even if all of its dependencies are updated and hence no further processing is done).

Summarizing

JsLibrary

will be included in the assembly because it always includes custom targets and custom targets. It will be a part make all

because we specified it all

when creating it.

JsLibrary

depends on ${PROJECT_JS_DIR}/${PROJECT}.js

, so the rule created by the custom command will be included in the build and checked every time it is built JsLibrary

. If it is deprecated it will be executed.

${PROJECT_JS_DIR}/${PROJECT}.js

in turn depends on ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp

because it was specified in the section of the DEPENDS

custom command creating .js

. So the rule described in the custom command creating glue.cpp

will also be included in the build and everything works as expected.

+3


source







All Articles