CMake and Flex/Bison - c++

I am converting my build system from configure/make to a cmake system
The system has some autogenerated files, from bison/flex. The original makefile commands are:
bison --defines=tokens.h --output=parser.cpp parser.y
flex --outfile=scanner.cpp scanner.l
I came across this ancient link which seems to explain how to do it, but when i run cmake with the following custom commands, nothing appears to happen (no error messages, no file generation)
FIND_PACKAGE(BISON REQUIRED)
IF(BISON_FOUND)
ADD_CUSTOM_COMMAND(
SOURCE ${CMAKE_SOURCE_DIR}/src/rcdgen/parser.y
COMMAND ${BISON_EXECUTABLE}
ARGS --defines=${CMAKE_SOURCE_DIR}/src/rcdgen/tokens.h
-o ${CMAKE_SOURCE_DIR}/src/rcdgen/parser.cpp
${CMAKE_SOURCE_DIR}/src/rcdgen/parser.y
COMMENT "Generating parser.cpp"
OUTPUT ${CMAKE_SOURCE_DIR}/src/rcdgen/parser.cpp
)
ENDIF(BISON_FOUND)
FIND_PACKAGE(FLEX REQUIRED)
IF(FLEX_FOUND)
ADD_CUSTOM_COMMAND(
SOURCE ${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.l
COMMAND ${FLEX_EXECUTABLE}
ARGS -o${CMAKE_SOURCE_DIR}/src/rcdgen/parser.cpp
${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.l
COMMENT "Generating scanner.cpp"
OUTPUT ${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.cpp
)
ENDIF(FLEX_FOUND)
I am new to cmake, so it's a bit confusing to me. Does anyone have any idea what a working custom_command would be?

The new hotness for bison usage is actually documented in FindBison So for a simple parser project:
find_package(BISON)
BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp
DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/parser.h)
add_executable(Foo main.cpp ${BISON_MyParser_OUTPUTS})
is what you'd do. Likewise for Flex.

The format of your add_custom_commands is not quite right, but they appear to be almost correct. There are two versions of add_custom_command, and the one you want is the one which produces an output file (the parts inside square brackets are optional):
add_custom_command(OUTPUT output1 [output2 ...]
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCY depend]
[DEPENDS [depends...]]
[IMPLICIT_DEPENDS <lang1> depend1
[<lang2> depend2] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM] [APPEND])
The idea is that the custom command only executes if the file specified as the OUTPUT of this command is used as an input elsewhere in the same CMakeLists.txt (e.g. in an add_library or add_executable call).
The custom command therefore will only run at build time (i.e. when you run make), not at configure time (when you run CMake), and only if you're building a target which directly or indirectly needs the OUTPUT file.
To fix your commands, I think the following should work (untested):
FIND_PACKAGE(BISON REQUIRED)
SET(BisonOutput ${CMAKE_SOURCE_DIR}/src/rcdgen/parser.cpp)
IF(BISON_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT ${BisonOutput}
COMMAND ${BISON_EXECUTABLE}
--defines=${CMAKE_SOURCE_DIR}/src/rcdgen/tokens.h
--output=${BisonOutput}
${CMAKE_SOURCE_DIR}/src/rcdgen/parser.y
COMMENT "Generating parser.cpp"
)
ENDIF()
FIND_PACKAGE(FLEX REQUIRED)
SET(FlexOutput ${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.cpp)
IF(FLEX_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT ${FlexOutput}
COMMAND ${FLEX_EXECUTABLE}
--outfile=${FlexOutput}
${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.l
COMMENT "Generating scanner.cpp"
)
ENDIF()
ADD_LIBRARY(MyLib ${BisonOutput} ${FlexOutput})

Related

How do I make CMake run a python script before building, in order to generate files for my project to be used in the build?

I have a python script that parses all of the C++ source files in the project's directory, looks for some stuff in the files, and then generates a file. This python script works fine, but I want it to automatically run before building my C++ project.
So basically, I want this python script to run before every build, so if any .h or .cpp files have been changed. I'd also like it to run if the python script itself has been changed. I have the python script in question, genenums.py, in the same directory as my C++ source files such as main.cpp, etc.
I've tried experimenting with add_custom_command based on documentation, but I can't get cmake to ever run this python script in any instance. I'm not sure how to make this work right, as I'm new to cmake.
Here's my current cmake file:
cmake_minimum_required(VERSION 3.9)
project(enum_test)
set(CMAKE_CXX_STANDARD 17)
include_directories(include)
find_package( PythonInterp 2.7 REQUIRED )
find_package( PythonLibs 2.7 REQUIRED )
add_custom_command(
COMMAND ${PYTHON_EXECUTABLE} genenums.py
DEPENDS genenums.py $(CMAKE_CURRENT_BINARY_DIR)
OUTPUT enums.h
WORKING_DIRECTORY $(CMAKE_CURRENT_BINARY_DIR)
COMMENT "Generating enums"
)
add_executable(enum_test main.cpp test.h test.cpp)
Ok, I have a foolproof, non-ugly way to have cmake run any kind of commands right before a build to build a dependency, waiting until the commands are done before doing the build.
add_custom_target(
run ALL
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genenums.py ${CMAKE_CURRENT_SOURCE_DIR}
BYPRODUCTS enums.h
COMMENT "Generating enums"
)
add_dependencies(enum_test run)
The two key parts are the add_custom_target and add_dependencies, both are required to make this work. Place both after the add_executable in CMakeLists.txt. enum_test refers to the target created by add_executable (the first name in its list), so you'd set that to your project's name.
You can name the custom target to whatever you like (I used run here) by changing the run in both add_custom_target and add_dependencies to something else.
There's one additional catch with add_custom_target... WORKING_DIRECTORY in that did nothing for my python script. Even when I tried to set the WORKING_DIRECTORY to ${CMAKE_CURRENT_SOURCE_DIR}, the script executed in the default ${CMAKE_CURRENT_BINARY_DIR} anyway.
So for this one catch, whatever commands you're using need to be able to take a command line argument of ${CMAKE_CURRENT_SOURCE_DIR} and use that to operate in the source directory properly (assuming that's your goal). That's why I have ${CMAKE_CURRENT_SOURCE_DIR} at the end of this line:
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genenums.py ${CMAKE_CURRENT_SOURCE_DIR}
Here's the full CMakeLists.txt with the working setup, should be fairly easy to adapt to any particular project's CMakeLists.txt.
cmake_minimum_required(VERSION 3.9)
project(enum_test)
set(CMAKE_CXX_STANDARD 17)
include_directories(include)
find_package( PythonInterp 2.7 REQUIRED )
add_executable(enum_test enums.h main.cpp test.h test.cpp)
add_custom_target(
run ALL
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genenums.py ${CMAKE_CURRENT_SOURCE_DIR}
BYPRODUCTS enums.h
COMMENT "Generating enums"
)
add_dependencies(enum_test run)

Compile without linking

I have a project set up with CMake, and I would like to build one object file in the project and output its llvm IR representation, in order to systematically inspect the generated output.
What I have so far is this:
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
separate_arguments(COMPILE_FLAGS UNIX_COMMAND ${CMAKE_CXX_FLAGS})
list(APPEND COMPILE_FLAGS "-S" "-emit-llvm" "-o" "example1.llvm")
add_custom_command(
TARGET example1 #example1 is the target that builds the actual executable
POST_BUILD
COMMAND ${CMAKE_CXX_COMPILER}
ARGS ${COMPILE_FLAGS} ${CMAKE_CURRENT_SOURCE_DIR}/calculator1.cpp
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Output the llvm IR representation"
)
endif()
Unfortunately ${CMAKE_CXX_FLAGS} does not contain all the arguments passed to clang in the actual compilation. I miss at least the extra include directories, and probably something else.
I tried
get_target_property(MYVAR example1 COMPILE_FLAGS)
and
get_property(
MYVAR
TARGET example1
PROPERTY COMPILE_FLAGS )
But they both fail.
How do I get all the options passed to the compiler (and not the linker)?
Should I take an entirely different approach?
Do you generate Makefile:s out of CMake? In that case you can use the property RULE_LAUNCH_COMPILE:
RULE_LAUNCH_COMPILE Specify a launcher for compile rules.
Makefile generators prefix compiler commands with the given launcher
command line. This is intended to allow launchers to intercept build
problems with high granularity. Non-Makefile generators currently
ignore this property.

CMake: Embed ELF into executable

I have a project that needs access to an ELF file embedded into the executable in a special section.
I was handcrafting Makefiles before and simply had a shell script where I used objcopy to copy the target I wanted to embed into an .o file, then link to this file in the executable.
# Create a new section and copy the binary there ($1=input $2=output name)
objcopy --input-target binary --output-target elf64-x86-64 \
--binary-architecture i386 $1 $2.o
Now I want to get rid of the custom Makefiles and use CMake to generate them. However, I don't see an easy way to link to such a file. I am able to create and add this file, but not to link against it:
# Invoke script to package module as a library
add_custom_command(OUTPUT ${PACKAGED_FILE}
COMMAND ./package.sh ${MODULE_FILE} ${PACKAGED_FILE}
WORKING_DIRECTORY ${MODULE_DIR}
DEPENDS ${MODULE_FILE}
COMMENT packaging file into ELF object
VERBATIM
)
add_custom_target(${PACKAGED_NAME} ALL DEPENDS ${PACKAGED_FILE})
I have tried to add it with:
target_link_libraries(binary ${PROJECT_BINARY_DIR}/${PACKAGED_FILE})
However, this fails because the file isn't there yet. It will be, but CMake doesn't know that. Adding the target name as a link library doesn't help either because it can't be found. Adding it as a also dependency doesn't help. Does anyone have an idea how this could be accomplished?
We are doing a similar thing in our project - the following part of our CMakeLists.txt does the trick:
set(PROJECT_EMBED_OBJ_FILES "")
set(PROJECT_EMBED_FILES "file1.elf" "file2.elf")
foreach(FILENAME ${PROJECT_EMBED_FILES})
get_filename_component(FILENAME_ONLY ${FILENAME} NAME)
get_filename_component(FILEPATH_ONLY ${FILENAME} PATH)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${FILENAME_ONLY}.o
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/${FILEPATH_ONLY}
COMMAND ${CMAKE_OBJCOPY}
ARGS -I binary -O elf64-x86-64 -B i386 ${FILENAME_ONLY} ${CMAKE_CURRENT_BINARY_DIR}/${FILENAME_ONLY}.o )
list(APPEND PROJECT_EMBED_OBJ_FILES ${CMAKE_CURRENT_BINARY_DIR}/${FILENAME_ONLY}.o)
message(STATUS "Objcopy'ing ${FILENAME}")
endforeach(FILENAME)
And then in the call to add_executable:
add_executable(projectname ${PROJECT_SOURCES} ${PROJECT_EMBED_OBJ_FILES})
You may try
add_custom_command(TARGET $(PROJECT_NAME).elf
POST_BUILD
COMMAND ${CMAKE_OBJCOPY} ARGS -O binary ${PROJECT_NAME}.elf \
${PROJECT_NAME}.bin)
Put this after your add_executable().
The POST_BUILD means execute after build.

Add custom build step in CMake

I'm trying to add a custom build step in CMake that generates some files. I haven't found a description how it works.
I have an project where source, header & implementation files have to be generated by ODB for C++. ODB takes class headers as arguments and generates source files that I want to use in my project.
Right now I have the following command in my CMakeLists.txt:
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND odb -o /home/david/dev/ --std c++11 -I/home/david/dev/ -d sqlite --generate- query --generate-schema ${PROMOTER_LIB_PREFIX}/entities/person.hpp
DEPENDS ${PROJECT_NAME}
VERBATIM
)
For a file person.hpp ODB should generate person-odb.hxx, person-odb.cxx, person-odb.ixx but the CMake command I''ve used doesn't generate anything. In a terminal this command works fine.
What am I doing wrong?
EDIT: The problem can be solved by adding the following lines:
set(FAKE_TARGET fakeTarget)
add_custom_target(fakeTarget
odb -o /home/david/dev/ --std c++11 -I/home/david/dev/ -d sqlite --generate-query --generate-schema ${PROMOTER_LIB_PREFIX}/entities/person.hpp
)
add_dependencies(${PROJECT_NAME} ${FAKE_TARGET})
For me, with something similar, I just use :
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND odb -o /home/david/dev/ --std c++11 -I/home/david/dev/ -d sqlite --generate- query --generate-schema ${PROMOTER_LIB_PREFIX}/entities/person.hpp
)
We don't use DEPENDS or VERBATIM.
The DEPENDS option specify that the command must be executed only after that the project you gave to this option is built.
EDIT :
Note that the PRE_BUILD option is only supported on Visual Studio 7 or later. For all other generators PRE_BUILD will be treated as PRE_LINK.
Maybe that's why it doesn't work for you.
A work around could be (a bit ugly) :
Create a fake project
Add your custom command on it as POST_BUILD
Make you current project dependent on the fake one
Way I'm using it is:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gen_icinstrtab.hpp
COMMAND xsltproc --output ${CMAKE_CURRENT_BINARY_DIR}/gen_icinstrtab.hpp ${CMAKE_SOURCE_DIR}/xml/genictabc.xslt ${CMAKE_SOURCE_DIR}/xml/icminstr.xml
)
add_executable(
du4
${CMAKE_CURRENT_BINARY_DIR}/gen_icinstrtab.hpp
.
.
.
)
The key was to add even .hpp files into add_executable block.

cmake run xxd as custom command

I've a rc directory I want to run xxd -i filename recursively in that directory.and add the generated files to my project.
I was checking some answer on lua. and I did it in a similar way.
SET(RESOURCE_COMPILER "xxd")
SET(COMPILED_RESOURCES "rc/base.css rc/common.js")
FOREACH(F ${COMPILED_RESOURCES})
ADD_CUSTOM_COMMAND(
OUTPUT "${COMPILED_RESOURCES}/${F}"
COMMAND ${RESOURCE_COMPILER} -i "${COMPILED_RESOURCES}/${F}"
COMMENT "Compiling ${F} to binary")
LIST (APPEND COMPILED_RESOURCES "${COMPILED_RESOURCES}/${F}")
ENDFOREACH()
but I don't see any file generated at all.
There are a couple of reasons you may not be seeing the output files. Your xxd command isn't well formed in the add_custom_command, but also the command will only be executed if the output file is required as a source in another CMake target (exe or lib) in the same CMakeLists.txt.
I'd change your snippet to something like:
SET(RESOURCE_COMPILER xxd)
FILE(GLOB_RECURSE COMPILED_RESOURCES "rc/*")
FOREACH(INPUT_FILE ${COMPILED_RESOURCES})
SET(OUTPUT_FILE ${INPUT_FILE}.hex)
ADD_CUSTOM_COMMAND(
OUTPUT ${OUTPUT_FILE}
COMMAND ${RESOURCE_COMPILER} -i ${INPUT_FILE} ${OUTPUT_FILE}
COMMENT "Compiling ${INPUT_FILE} to binary")
LIST(APPEND COMPILED_RESOURCES ${OUTPUT_FILE})
ENDFOREACH()
Then if you have another target which depends on the ${OUTPUT_FILE}s the command will be executed when that target is being built:
ADD_EXECUTABLE(MY_EXE main.cc ${COMPILED_RESOURCES})