CMake BISON_TARGET prevent header generation - cmake

Have looked everywhere. Is there no way to prevent CMake from generating a header file with BISON_TARGET?

Heres what I ended up doing
# Create target for xml
ADD_CUSTOM_TARGET(xml echo "Creating xml.cc" DEPENDS xml.cc)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xml.cc
COMMAND ${BISON_EXECUTABLE}
ARGS -y ${CMAKE_CURRENT_SOURCE_DIR}/xml.y -p xml -o ${CMAKE_CURRENT_BINARY_DIR}/xml.cc
)
then you later you need
add_executable (parse
${SOURCES}
...
xml.cc
)
add_dependencies(parse xml)
and
target_include_directories(parse PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
If you want generated files in the build dir.

Related

Copy File to Executable Directory Recopy on Modified

I'm trying to copy a file to the same directory where the executable ends up. This means including the configuration type "RelWithDebInfo" directory with Visual Studio. Any CMake variable such as "CMAKE_BINARY_DIR" and similar don't include this folder in the path.
add_executable(${PROJECT_NAME} main.cpp)
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/copy_this.txt copy_this.txt
COMMENT "Copying..."
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/copy_this.txt
)
The above code works but it doesn't cause the file to be recopied with it is modified. The only other solution I found where it does copy when it is to use add_custom_command(OUTPUT copy_this.txt ...) but it doesn't copy the file into the correct folder.
add_custom_command(
OUTPUT copy_this.txt # this expects the file to be in ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/copy_this.txt copy_this.txt
COMMENT "Copying..."
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/copy_this.txt
)
add_custom_target(target_copy_this.txt DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/copy_this.txt)
add_dependencies(${PROJECT_NAME} target_copy_this.txt)
The add_custom_command needs to be updated to specify where the file needs to be copied. In both examples the file is copied into the current working directory because the path is not specified. Here is an example of how to copy to the home directory.
set(newloc ~)
add_custom_command(
OUTPUT ${newloc}/copy_this.txt
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/copy_this.txt ${newloc}/copy_this.txt
COMMENT "Copying to ${newloc}"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/copy_this.txt
)
add_custom_target(target_copy_this.txt ALL DEPENDS copy_this.txt)
It seems that you want the file to be copied to where one of the targets winds up. In visual studio this could be ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} or ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR} depending upon what else is going on in the CMakeLists.txt.
Using this example and setting newloc to ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} you will get the following output:
cmake --build . --config RelWithDebInfo
CustomBuild:
Copying to C:/Users/ZZZ/Projects/test/bld/RelWithDebInfo

During build, how to create a directory for a file which is generated by some COMMAND?

I'm writing a custom command in CMake to convert a file to binary format at build time. However, the tool I'm using requires directory for a file to be pre-existed; it doesn't create a directory automatically.
Currently my CMake macro looks like this:
MACRO(ConvertToBinary _name)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_BINARY_DIR}/${_name}.bin
COMMAND ${EXE_DIR}/toBinary -i ${CMAKE_CURRENT_SOURCE_DIR}/${_name} -o ${CMAKE_BINARY_DIR}/${_name}.bin
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_name}
)
ENDMACRO(ConvertToBinary)
This macro doesn't work for _name parameter equal, e.g., to "test/sample.txt", because the tool is run with test/ folder under ${CMAKE_BINARY_DIR} being not existed.
How to create the directory before the tool, generating the file, is run?
I have tried to overcome the problem by pre-creating the file (and directory) with the help of CMake. So the tool will be run with the directory created, and can override the output file. I have tried the following:
MACRO(ConvertToBinary _name)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_BINARY_DIR}/${_name}.bin
FILE(WRITE ${CMAKE_BINARY_DIR}/${_name}.bin "Dummy")
COMMAND ${EXE_DIR}/toBinary -i ${CMAKE_CURRENT_SOURCE_DIR}/${_name} -o ${CMAKE_BINARY_DIR}/${_name}.bin
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_name}
)
ENDMACRO(ConvertToBinary)
But it did not work. I can't find information on how to create file at build time with CMake, so any help is appreciated.
In CMake you may extract directory component of the file and create this directory.
Below code can be used for a tool, which generates a file but doesn't create directory for it.
# Assume some tool generates file '${file}', but don't create directory for it.
#
# Extract directory component for a file
get_filename_component(_dir ${file} DIRECTORY)
add_custom_command(OUTPUT ${file}
COMMAND ${CMAKE_COMMAND} -E make_directory ${_dir} # Create output directory
COMMAND <tool-which-generates-file> ... ${file}
)
See also that question about ways for create a directory in CMake.

How to specify different folder structure for CPack TGZ generator?

I have a CMake project that installs things to a system according to the install command as follows:
install (
TARGETS myTarget
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
)
make install works perfectly. And then I want to have a binary archive:
set(CPACK_GENERATOR "TGZ")
make package produces an tar.gz file with the same folder structure as the install command specified. However, I want to have a flat structure, that is, put everything (both executables and libraries) in "prefix", without the "bin" and "lib" directory.
Is that possible? May be with some clever use of the component system, the build type system, or CPACK_PROJECT_CONFIG_FILE?
At the end I added a custom install script, which detects whether it is run by CPack by looking at CMAKE_INSTALL_PREFIX, and restructure the install tree if necessary.
Here is my solution:
In CMakeLists.txt, after all the install() commands, add
install(SCRIPT "${CMAKE_SOURCE_DIR}/cmake/flatten.cmake")
Add a file, "cmake/flatten.cmake", with content as follows
# Detect if the install is run by CPack.
if (${CMAKE_INSTALL_PREFIX} MATCHES "/_CPack_Packages/.*/(TGZ|ZIP)/")
# Flatten the directory structure such that everything except the header files is placed in root.
file(GLOB bin_files LIST_DIRECTORIES FALSE ${CMAKE_INSTALL_PREFIX}/bin/*)
file(GLOB lib_files LIST_DIRECTORIES FALSE ${CMAKE_INSTALL_PREFIX}/lib/*)
foreach(file ${bin_files} ${lib_files})
get_filename_component(file_name ${file} NAME)
execute_process(
COMMAND ${CMAKE_COMMAND} -E rename
${file}
${CMAKE_INSTALL_PREFIX}/${file_name}
)
endforeach()
execute_process( COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_INSTALL_PREFIX}/bin)
execute_process( COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_INSTALL_PREFIX}/lib)
endif()

Empty RUNTIME_OUTPUT_DIRECTORY

Working on a project using CMake. This project contains an executable and a python script. These two files should be compiled/copied in the same directory at build.
I try something like :
add_executable( ${myTarget} ${all_c_sources} )
add_custom_command(
TARGET ${myTarget} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${pythonScriptPath} ${RUNTIME_OUTPUT_DIRECTORY}/
)
The executable is well build in a default location like ${CMAKE_BINARY_DIR}/Debug but the copy of the python script failed :
c:\Program Files (x86)\CMake\bin\cmake.exe" -E copy C:/.../script.py /\r
My goal is to use CMake default behavior as mush as possible.
Is there a simple way to get the default output path ?
Thanks !
Something like this:
add_custom_command(TARGET ${LIBRARY_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${LIBRARY_NAME}>
$<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/path/to/where/module/should/be
COMMENT "Copying file to Runtime directory: " $<TARGET_FILE:${LIBRARY_NAME}>
)
Adjust it to your needs.
Read about CMake Generator Expressions if you need to know more.

Changing the layout when creating a TGZ archive

I use CMake to manage a project with the following layout:
ProjectA/
include
doc
test
ProjectB
include
doc
test
I would like to use CPack to package up a tar.gz source archive with the following layout:
include/
ProjectA/
doc
test
ProjectB/
doc
test
where the new top-level include contains all include files.
I tried achieving this by running a CMake script through CPACK_INSTALL_SCRIPT, but this script runs before the files are created. Where can I hook into CPack to get that effect?
It also seems that install has no influence on what make
package_source does, but it has an effect on make
package. Unfortunately make package will also build and package
libraries, which is something I don't want to happen. I want a pure
source distribution ala make dist.
You can call install(DIRECTORY include DESTINATION include) on headers from both ProjectA and ProjectB and install them into the same dir. This would cause CPack to place them together in the generated package.
Update
Okay, i've managed to do this with CPACK_INSTALL_SCRIPT variable.
I've created following script:
set(CMAKE_SOURCE_DIR #CMAKE_SOURCE_DIR#)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/A/ ${CMAKE_SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/B/ ${CMAKE_SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_SOURCE_DIR}/A)
execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_SOURCE_DIR}/B)
In the CMakeLists.txt i've populated it with actual value of CMAKE_SOURCE_DIR:
configure_file(CPackScript.cmake CPackScript.cmake #ONLY)
Finally, i've added set(CPACK_INSTALL_SCRIPT ${CMAKE_BINARY_DIR}/CPackScript.cmake) and voila! Generated packages now have include dir with headers from both A/ and B/, while A/ and B/ dirs don't exist.
Another possible approach is to completely bypass CPack for the generation of the TGZ archive and simply use a CMake custom target which generates the archive:
project (MyProject)
set (DIST_TEMP_DIR "${CMAKE_BINARY_DIR}/dist")
make_directory(${DIST_TEMP_DIR})
add_custom_target(dist
COMMAND ${CMAKE_COMMAND} -E remove_directory "${DIST_TEMP_DIR}/${PROJECT_NAME}/"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/ProjectA/include" "${DIST_TEMP_DIR}/${PROJECT_NAME}/include"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/ProjectA/test" "${DIST_TEMP_DIR}/${PROJECT_NAME}/ProjectA/test"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/ProjectA/doc" "${DIST_TEMP_DIR}/${PROJECT_NAME}/ProjectB/doc"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/ProjectB/include" "${DIST_TEMP_DIR}/${PROJECT_NAME}/include"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/ProjectB/doc" "${DIST_TEMP_DIR}/${PROJECT_NAME}/ProjectA/doc"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/ProjectB/test" "${DIST_TEMP_DIR}/${PROJECT_NAME}/ProjectB/test"
COMMAND ${CMAKE_COMMAND} -E tar cvz "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.tar.gz" "${DIST_TEMP_DIR}/${PROJECT_NAME}/"
COMMENT "Building ${PROJECT_NAME}.tar.gz"
WORKING_DIRECTORY "${DIST_TEMP_DIR}"
)
The custom target dist first sets up the desired structure of the archive in a temporary directory inside the build folder by invoking CMake in command mode with multiple copy_directory commands. Then it generates the tar.gz archive by using the tar command mode sub-command.
I am not sure what excactly is not working for you.
This is what works for me for the ZIP generator on windows. I will try to find a linux machine to see if this works with TGZ as well (EDIT: it does):
Directory structure:
CMakeLists.txt
ProjectA/
doc
foo.txt
include
foo.h
test
foo.test
ProjectB/
doc
bar.txt
include
bar.h
test
bar.test
ProjectA/CMakeLists.txt
project( ProjectA )
INSTALL( DIRECTORY include DESTINATION . )
INSTALL( DIRECTORY doc DESTINATION ${PROJECT_NAME}/ )
INSTALL( DIRECTORY test DESTINATION ${PROJECT_NAME}/ )
ProjectB/CMakeLists.txt
project( ProjectB )
INSTALL( DIRECTORY include DESTINATION . )
INSTALL( DIRECTORY doc DESTINATION ${PROJECT_NAME}/ )
INSTALL( DIRECTORY test DESTINATION ${PROJECT_NAME}/ )
CMakeLists.txt:
project( MyProject )
ADD_SUBDIRECTORY(ProjectA)
ADD_SUBDIRECTORY(ProjectB)
INCLUDE(CPack)
If I create the package, I get
MyProject-0.1.1-win32.zip
MyProject-0.1.1-win32
include
bar.h
foo.h
ProjectA
doc
foo.txt
test
foo.test
ProjectB
doc
bar.txt
test
bar.test
Is that what you intended?
Source packages
For source package creation, CPack by default ignores the install commands and installs/copies all directories that are specified in CPACK_SOURCE_INSTALLED_DIRECTORIES. This variable contains pairs of source and destination directories. It defaults to "${CMAKE_SOURCE_DIR};/" if not manually set. To be precise, it globs these directories, ignoring all files in CPACK_SOURCE_IGNORE_FILES which defaults to all major VCS bookkeeping files (see your CPackSourceConfig.cmake for example).
You you could do the following:
CMakeLists.txt
project( MyProject )
SET( PROJECTS ProjectA ProjectB )
SET(CPACK_SOURCE_INSTALLED_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};/")
FOREACH( p ${PROJECTS} )
ADD_SUBDIRECTORY( ${p} )
LIST( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR/${p}/include include )
ENDFOREACH()
INCLUDE(CPack)
or add the manipulation to of CPACK_SOURCE_INSTALLED_DIRECTORIES to the respective project files.
However: This will install your include directories to the top-level include directory, but additionally still create another copy inside the project directories due to globbing. You could probably create additional directory-pairs for your doc and test directories and skip the initialization of the CPACK_SOURCE_INSTALLED_DIRECTORIES in the SET command. If you do this, you will need to find a way to install/copy your project-specific CMake files.
BIG CAVEAT: If ProjectAor ProjectB refer to the project-local include directory (eg. with INCLUDE_DIRECTORIES(...) you will break your CMake code, rendering the source installation (partially) useless. So you might want to rethink your idea of the top-level include directory.