FLEX/BISON generate location.hh, position.hh, stack.hh in different folder - c++

I have folder structure like this
include/
src/
| parser.yy
| scanner.ll
and in the src/CMakeLists.txt:
SET(BisonOutput ${CMAKE_SOURCE_DIR}/src/_parser.cpp)
IF(BISON_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT ${BisonOutput}
COMMAND ${BISON_EXECUTABLE}
--defines=${CMAKE_SOURCE_DIR}/include/_parser.hpp
--output=${BisonOutput}
${CMAKE_SOURCE_DIR}/src/parser.yy
COMMENT "Generating parser"
)
ENDIF()
SET(FlexOutput ${CMAKE_SOURCE_DIR}/src/_scanner.cpp)
IF(FLEX_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT ${FlexOutput}
COMMAND ${FLEX_EXECUTABLE}
--outfile=${FlexOutput}
${CMAKE_SOURCE_DIR}/src/scanner.ll
COMMENT "Generating scanner"
)
ENDIF()
However the files locations.hh, position.hh and stack.hh are generated inside the src directory. Is it possible to somehow specify that i want these files generated inside the include directory?
I am using Bison 3.0.4 and Flex 2.6.4

I'm not sure if Bison/Flex allows you to generate them in a separate location, but you can use CMake to copy them to the include directory once they are generated. Add another add_custom_command call with PRE_BUILD to ensure they are copied before building your target:
ADD_CUSTOM_COMMAND(
TARGET MyTarget PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/src/locations.hh ${CMAKE_SOURCE_DIR}/include
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/src/position.hh ${CMAKE_SOURCE_DIR}/include
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/src/stack.hh ${CMAKE_SOURCE_DIR}/include
)

Related

How do file paths and including files/directories with CMake work? [duplicate]

Copying directory from source tree to binary tree. For example: How to copy www to bin folder.
work
├─bin
└─src
├─doing
│ └─www
├─include
└─lib
Thanks.
Since version 2.8, the file command has a COPY sub-command:
file(COPY yourDir DESTINATION yourDestination)
Note that:
Relative input paths are evaluated with respect to the current source
directory, and a relative destination is evaluated with respect to the
current build directory
With CMake 2.8 or later, use the file(COPY ...) command.
With CMake versions below 2.8, the following macro copies files from one directory to another. If you don't want to substitute variables in the copied files, then change the configure_file #ONLY argument (for example to COPYONLY).
# Copy files from source directory to destination directory, substituting any
# variables. Create destination directory if it does not exist.
macro(configure_files srcDir destDir)
message(STATUS "Configuring directory ${destDir}")
make_directory(${destDir})
file(GLOB templateFiles RELATIVE ${srcDir} "${srcDir}/*")
foreach(templateFile ${templateFiles})
set(srcTemplatePath ${srcDir}/${templateFile})
if(NOT IS_DIRECTORY ${srcTemplatePath})
message(STATUS "Configuring file ${templateFile}")
configure_file(
${srcTemplatePath}
${destDir}/${templateFile}
#ONLY)
endif(NOT IS_DIRECTORY ${srcTemplatePath})
endforeach(templateFile)
endmacro(configure_files)
As nobody has mentioned cmake -E copy_directory as a custom target, here's what I've used:
add_custom_target(copy-runtime-files ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/runtime-files-dir ${CMAKE_BINARY_DIR}/runtime-files-dir
DEPENDS ${MY_TARGET})
The configure command will only copy files when cmake is run. Another option is to create a new target, and use the custom_command option. Here's one that I use (if you run it more than once, you'll have to modify the add_custom_target line to make it unique for each call).
macro(copy_files GLOBPAT DESTINATION)
file(GLOB COPY_FILES
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${GLOBPAT})
add_custom_target(copy ALL
COMMENT "Copying files: ${GLOBPAT}")
foreach(FILENAME ${COPY_FILES})
set(SRC "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
set(DST "${DESTINATION}/${FILENAME}")
add_custom_command(
TARGET copy
COMMAND ${CMAKE_COMMAND} -E copy ${SRC} ${DST}
)
endforeach(FILENAME)
endmacro(copy_files)
Use execute_process and call cmake -E. If you want a deep copy, you can use the copy_directory command. Even better, you could create a symlink (if your platform supports it) with the create_symlink command. The latter can be achieved like this:
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR}/path/to/www
${CMAKE_BINARY_DIR}/path/to/www)
From: http://www.cmake.org/pipermail/cmake/2009-March/028299.html
Thank! That is really helpful advice to use bunch of add_custom_target and add_custom_command. I wrote the following function to use everywhere in my projects. Is also specifies the installation rule. I use it primarily to export interface header files.
#
# export file: copy it to the build tree on every build invocation and add rule for installation
#
function (cm_export_file FILE DEST)
if (NOT TARGET export-files)
add_custom_target(export-files ALL COMMENT "Exporting files into build tree")
endif (NOT TARGET export-files)
get_filename_component(FILENAME "${FILE}" NAME)
add_custom_command(TARGET export-files COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}" "${CMAKE_CURRENT_BINARY_DIR}/${DEST}/${FILENAME}")
install(FILES "${FILE}" DESTINATION "${DEST}")
endfunction (cm_export_file)
Usage looks like this:
cm_export_file("API/someHeader0.hpp" "include/API/")
cm_export_file("API/someHeader1.hpp" "include/API/")
Based on the answer from Seth Johnson; wrote for more convenience:
# Copy files
macro(resource_files files)
foreach(file ${files})
message(STATUS "Copying resource ${file}")
file(COPY ${file} DESTINATION ${Work_Directory})
endforeach()
endmacro()
# Copy directories
macro(resource_dirs dirs)
foreach(dir ${dirs})
# Replace / at the end of the path (copy dir content VS copy dir)
string(REGEX REPLACE "/+$" "" dirclean "${dir}")
message(STATUS "Copying resource ${dirclean}")
file(COPY ${dirclean} DESTINATION ${Work_Directory})
endforeach()
endmacro()

CMake generates circular dependencies for VS project, but not make files. How to avoid?

This sample is boiled down from an actual project I am working on; an MWE of sorts (well, not working would be more appropriate).
Consider the following project structure:
.
├── CMakeLists.txt
├── build
├── include
│   └── hello.hpp
└── src
└── hello.cpp
The build directory is used to conduct the build and will contain the build artifacts and intermediate files. The contents of the remaining files will be given at the bottom of this question.
The idea is to install() the built library along with its header (and some other stuff in the real project).
add_custom_command(
TARGET ${PRJNAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} --build . --target install
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
VERBATIM
)
... along with the install() is meant to accomplish this and does for the generators Unix Makefiles and NMake Makefiles, but creates a circular dependency for Visual Studio 16 2019 (also for Visual Studio 14 2015, but I didn't test any further than that).
Now my immediate reaction was, that this was an inconsistency across generators, but on the other hand the project generation with anything other than make files has been - IMO - one of the weaknesses of CMake all along.
For now my workaround is simply to use the NMake Makefiles, but the downside of that approach is that I have to "detect" Visual Studio before and use vcvarsall.bat, vcvars32.bat and friends. But that's a small nuisance compared to the circular dependency.
How can I use one of the Visual Studio project generators to achieve what I want and dodge that circular dependency?
On Windows I am using CMake 3.15.1 (latest at the time of writing).
NB: I realize that I could use something to the effect of ${CMAKE_COMMAND} --build . --target install by creating custom commands/targets sprinkled with a few file() commands. But that wouldn't keep it DRY now, would it?
CMakeLists.txt
set(CMAKE_RULE_MESSAGES OFF)
set(CMAKE_VERBOSE_MAKEFILE ON)
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
set(PRJNAME FOOBAR)
project (${PRJNAME})
set(SOURCE_DIR "src")
set(HEADER_DIR "include")
set(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/install-target")
set(PUBLIC_HEADER "${HEADER_DIR}/hello.hpp")
set(PROJ_SOURCES "${SOURCE_DIR}/hello.cpp")
add_library(${PRJNAME} SHARED ${PROJ_SOURCES})
list(TRANSFORM PUBLIC_HEADER PREPEND "${CMAKE_CURRENT_BINARY_DIR}/" OUTPUT_VARIABLE PUBLIC_HEADER_PP)
set_target_properties(
${PRJNAME}
PROPERTIES
CXX_STANDARD 11
CXX_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON
PUBLIC_HEADER "${PUBLIC_HEADER_PP}"
POSITION_INDEPENDENT_CODE 1
)
set(CMAKE_INSTALL_PREFIX ${TARGET_DIR})
set(CMAKE_INSTALL_LIBDIR lib)
set(CMAKE_INSTALL_INCLUDEDIR ${HEADER_DIR})
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${HEADER_DIR}")
configure_file("${PUBLIC_HEADER}" "${CMAKE_CURRENT_BINARY_DIR}/${HEADER_DIR}/" COPYONLY)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/${HEADER_DIR}")
add_custom_command(
TARGET ${PRJNAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} --build . --target install
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
VERBATIM
)
set(PKGNAME "foobar-package.zip")
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PKGNAME}
COMMAND ${CMAKE_COMMAND} -E tar cv "${CMAKE_CURRENT_BINARY_DIR}/${PKGNAME}" -- .
WORKING_DIRECTORY "${TARGET_DIR}"
VERBATIM
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_CURRENT_BINARY_DIR}/${PKGNAME})
add_custom_target(
lib
DEPENDS ${PRJNAME}
)
src/hello.cpp
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
BOOL APIENTRY DllMain(HMODULE, DWORD, LPVOID) { return TRUE; }
#endif
#include "hello.hpp"
int hello() { return 42; }
include/hello.cpp
#pragma once
#ifdef _WIN32
# ifdef FOOBAR_EXPORTS
# define FOOBAR_API __declspec(dllexport)
# else
# define FOOBAR_API __declspec(dllimport)
# endif
#else
# define FOOBAR_API
#endif
FOOBAR_API int hello();
It seems to me that your use case is beyond what CMake was designed for.
You are trying to build the INSTALL target, which in turn builds the FOOBAR target, which in turn calls the INSTALL command.
If we break the chain here by splitting into two different targets: FOOBAR and FOOBAR_INSTALL like so
add_custom_target(${PRJNAME}_INSTALL ALL
${CMAKE_COMMAND} --build . --target install
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
VERBATIM
)
we would still get the circular reference through the ALL_BUILD target.
So if we remove the ALL argument the reference would be broken but the target won't be called from the default build command which is not better than calling make and make install.
The proper place to break the dependency would be between the INSTALL and other targets. Instead of building the INSTALL target you can call the generated cmake_install.cmake script directly:
add_custom_command(
TARGET ${PRJNAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -D CMAKE_INSTALL_CONFIG_NAME=$<CONFIG> -P cmake_install.cmake
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
VERBATIM
)

CMake - Alternative to generator expression for build output directory?

I have a cmake build system gone wild. Before supporting IDEs, everything was ok.
I need to copy files (shaders in this case) to the build directory. They need to be copied when they've changed, regardless of whether the main target is built or not.
I had success before, as I could add a custom command with ${CMAKE_CURRENT_BINARY_DIR}, add dependencies later and everything was fine.
The problem is, when using a generator expression for the command output, it creates a dependency from my custom command to the main target. This means adding a dependency backwards (which is needed to trigger the copy) throws an error because of cyclic dependencies.
This is what I have so far, which doesn't work because the custom target (thus custom command) is not triggered when the main target doesn't need rebuilding.
set(SHADER_IN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders)
file(GLOB_RECURSE SHADERS "${SHADER_IN_DIR}/*.glsl")
add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${PROJECT_NAME}>/shaders/)
set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/.stamps)
add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${STAMP_DIR})
set(STAMP_FILES "")
foreach(SHADER ${SHADERS})
get_filename_component(SHADER_FILENAME ${SHADER} NAME)
set(STAMP_FILE ${STAMP_DIR}/${SHADER_FILENAME}.stamp)
add_custom_command(
OUTPUT ${STAMP_FILE}
COMMAND ${CMAKE_COMMAND} -E touch ${STAMP_FILE}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SHADER} $<TARGET_FILE_DIR:${PROJECT_NAME}>/shaders/${SHADER_FILENAME}
DEPENDS ${SHADER}
)
list(APPEND STAMP_FILES ${STAMP_FILE})
endforeach()
add_custom_target(Shaders
SOURCES ${SHADERS}
DEPENDS ${STAMP_FILES})
# Need to add dependency here! But I can't :(
So, is there any other way to get what output directory will be used in an IDE? All "solutions" I've read to force building a target have failed (they pretty much all rely on add_dependencies).
Thank you for saving my sanity.
In the end, instead of trying to find out where the IDE is going to output the binary, I forced output in a predictable bin/ dir.
set(BINARY_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})
foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})
endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)

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})

CMake: How to copy only specific file extensions from one directory into another

I am using the following custom command to copy all the files within the config directory into the build directory. The problem is that I don't want the .svn directory to be copied as well. I am looking for a way to either exclude the .svn directory or to copy files with specific extension. e.g. I want only files with xml or conf extensions to be copied. What should I do?
add_custom_command(TARGET MyTarget PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/config $<TARGET_FILE_DIR:MyTarget>)
related question
To copy just the .xml and .conf files, you can use the file(GLOB ...) command:
# Gather list of all .xml and .conf files in "/config"
file(GLOB ConfigFiles ${CMAKE_SOURCE_DIR}/config/*.xml
${CMAKE_SOURCE_DIR}/config/*.conf)
foreach(ConfigFile ${ConfigFiles})
add_custom_command(TARGET MyTarget PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E
copy ${ConfigFile} $<TARGET_FILE_DIR:MyTarget>)
endforeach()
It's a similar process to get all files not in the .svn subdirectory:
# Gather list of all files in "/config"
file(GLOB ConfigFiles RELATIVE ${CMAKE_SOURCE_DIR}/config
${CMAKE_SOURCE_DIR}/config/*)
# Gather list of all files in "/config/.svn"
file(GLOB SvnConfigFiles RELATIVE ${CMAKE_SOURCE_DIR}/config
${CMAKE_SOURCE_DIR}/config/.svn/*)
# Remove ".svn" and its contents from the list
list(REMOVE_ITEM ConfigFiles .svn ${SvnConfigFiles})
foreach(ConfigFile ${ConfigFiles})
add_custom_command(TARGET MyTarget PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E
copy ${CMAKE_SOURCE_DIR}/config/${ConfigFile}
$<TARGET_FILE_DIR:MyTarget>)
endforeach()