CMake qt5_add_translation, how to specify the output path? - cmake

I use qt5_add_translation to run lrelease and generate the .qm files. By default the .qm files are put at the root level of the build dir, no matter where you put the .ts files in the source dir.
How can I specify a subdir for those files in the build ?

Set a property on the .ts files before calling the Qt macro :
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION your_output_path)
Where TS_FILES contains the list of the .ts files and your_output_path is the path where to put the .qm files (relative to the build directory or absolute).
Because the macro will retrieve the property to make the path of the .qm files (tested with Qt 5.9) :
get_source_file_property(output_location ${_abs_FILE} OUTPUT_LOCATION)
if(output_location)
file(MAKE_DIRECTORY "${output_location}")
set(qm "${output_location}/${qm}.qm")
else()
set(qm "${CMAKE_CURRENT_BINARY_DIR}/${qm}.qm")
endif()

Use manual call of lrelease and lupdate utilities
set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/translations")
set(TS_FILES
"${TS_DIR}/${PROJECT_NAME}_ru_RU.ts"
)
find_program(LUPDATE_EXECUTABLE lupdate)
find_program(LRELEASE_EXECUTABLE lrelease)
foreach(_ts_file ${TS_FILES})
execute_process(
COMMAND ${LUPDATE_EXECUTABLE} -recursive ${CMAKE_SOURCE_DIR} -ts ${_ts_file})
execute_process(
COMMAND ${LRELEASE_EXECUTABLE} ${_ts_file})
endforeach()

Related

CMake only copy non-cmake files

I am currently building a shared library along with an exectuable with cmake. The exectuable and shared library must both have a specific folder structure that they are built into, and share the same folder.
So, after building both targets, I copy the required files to this folder (along with a couple extra dependencies that the exectuable has).
I can copy the exectuable's binary output directory fine, but when I do, I want to be able to leave out the extra files and folders that cmake generates, ie cmake_install.cmake and CMakeFiles/.
Is there a way to copy the exectuable along with its dependencies, while leaving out these files? There's a few extra shared libraries that are external to the executable target that also need to be distributed with it, which is why I also want to copy these.
These are my current CMakeLists.txt:
CMakeLists.txt
add_library(my_library SHARED src/main.cpp)
add_subdirectory(executable)
add_custom_command(
TARGET my_library
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:my_library>
$<TARGET_FILE_DIR:my_library>/bin/${PLATFORM_NAME}${PROCESSOR_ARCH}/$<TARGET_FILE_NAME:my_library>
)
executable/CMakeLists.txt
add_executable(executable main.cpp)
target_link_libraries(executable PRIVATE some_external_libraries...)
add_custom_command(
TARGET executable
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
$<TARGET_FILE_DIR:executable>
$<TARGET_FILE_DIR:my_library>/bin/${PLATFORM_NAME}${PROCESSOR_ARCH}
)
Provide logic for installing the project via the install command:
CMakeLists.txt
...
set(CMAKE_INSTALL_BINDIR bin/${PLATFORM_NAME}${PROCESSOR_ARCH}) # set exe/dll output dir
set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_BINDIR}) # not recommended; so files only; use INSTALL_RPATH for exe instead
add_library(my_library SHARED src/main.cpp)
install(TARGETS my_library RUNTIME LIBRARY)
add_subdirectory(executable)
executable/CMakeLists.txt
add_executable(executable main.cpp)
target_link_libraries(executable PRIVATE some_external_libraries...)
install(TARGETS executable RUNTIME)
this allows you to use
cmake --install build_dir --prefix install_dir
optionally passing --config <Configuration> for multi config generators to install copy the files built for the cmake project using build_dir as build directory to the directory install_dir. The files will be located in install_dir/bin/${PLATFORM_NAME}${PROCESSOR_ARCH} (variables replaced with the content of the cmake variables during configuration).
Note: If this is just an attempt to make the executable runnable from the build tree, e.g. using the Visual Studio Debugger, you could instead simply set the CMAKE_RUNTIME_OUTPUT_DIRECTORY to an absolute path in the toplevel CMakeLists.txt which results in all the dlls and executables where you do not set the RUNTIME_OUTPUT_DIRECTORY or OUTPUT_DIRECTORY properties yourself going into the same directory. Alternatively you could set the VS_DEBUGGER_ENVIRONMENT target property to something like "PATH=$<TARGET_FILE_DIR:my_library>;$ENV{PATH}" to run the debugger with the PATH environment variable set in a way allowing the executable to locate the dll.

How to include generated files for compilation with cmake?

I have a set of .xsd files in a subdirectory 'xsd'. I generate a set of .hxx and cxx files for XML-binding with an external command.
add_custom_command(
PRE_BUILD
OUTPUT ${PROJECT_SOURCE_DIR}/xsd/file1.hxx ${PROJECT_SOURCE_DIR}/xsd/file1.cxx
COMMAND ${XSD_EXECUTABLE} cxx-tree
--file-list-prologue 'set(XSD_GENERATED_FILES '
--file-list ${PROJECT_SOURCE_DIR}/cmake_xsd_filelist.txt
--file-list-epilogue ')'
--output-dir ${PROJECT_SOURCE_DIR}/xsd
${XSD_SOURCE_FILES}
DEPENDS ${XSD_SOURCE_FILES}
)
The tool creates a list of generated files. I have it in the following form:
set(XSD_GENERATED_FILES
file1.cpp
file1.hpp
file2.cpp
file2.hpp
)
Fine up to here.
Now the part where I don't know how to continue. I want to include the generated file list and add them to the executable.
include(${PROJECT_SOURCE_DIR}/cmake_xsd_filelist.txt)
add_executable(Prog ${SOURCE_FILES} ${XSD_GENERATED_FILES})
But this does not do what I want. Actually, it does nothing because initially cmake_xsd_filelist.txt is empty.
My goal is the following:
when a file in the 'xsd' folder changes, execute XSD_EXECUTABLE for generating the .cpp and hpp files.
only compile once the generated .cpp files when they have changed
add the generated source files to the executable.
Is this even possible with cmake? If yes, how?
Include sources
include(${PROJECT_SOURCE_DIR}/cmake_xsd_filelist.txt)
add_executable(Prog ${SOURCE_FILES} ${XSD_GENERATED_FILES})
This means that you need to have a cmake_xsd_filelist.txt file on configure step, i.e. xsd must be invoked by execute_process. Also I think it's better to generate files to binary directory (follow out-of-source concept):
# Create directory if needed
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/generated")
execute_process(
COMMAND
${XSD_EXECUTABLE} cxx-tree
--file-list-prologue 'set(XSD_GENERATED_FILES '
--file-list "${CMAKE_BINARY_DIR}/generated/cmake_xsd_filelist.txt"
--file-list-epilogue ')'
--output-dir "${CMAKE_BINARY_DIR}/generated/xsd"
${XSD_SOURCE_FILES}
RESULT_VARIABLE result
)
Do not forget to check successfull exit status:
if(NOT result EQUAL 0)
message(FATAL_ERROR "XSD failed")
endif()
Now you can include sources:
include(${CMAKE_BINARY_DIR}/generated/cmake_xsd_filelist.txt)
add_executable(Prog ${SOURCE_FILES} ${XSD_GENERATED_FILES})
XSD sources update
when a file in the 'xsd' folder changes, execute XSD_EXECUTABLE
for generating the .cpp and hpp files.
I.e. CMake must run reconfigure if one of the xsd file changes. Here is the trick that helps:
foreach(x ${XSD_SOURCE_FILES})
configure_file(${x} ${x} COPYONLY)
endforeach()
Now if any of the XSD_SOURCE_FILES changes CMake will reconfigure the project effectively re-running XSD_EXECUTABLE and re-including cmake_xsd_filelist.txt.

Cmake: Create directory command in suddirectory's CMakeLists.txt file

I have included a subdirectory in root's CMakeLists.txt with explicitly specifying the binary_dir as follow
add_subdirectory(subdir_with_CMakeLists.txt out_dir)
all the target are built into the out_dir as it supposed to, however MAKE_DIRECTORY command - file(MAKE_DIRECTORY some_dir) inside the included CMakeLists.txt creates the directory relative to the location of subdirectory's CMakeLists.txt, not inside the out_dir as I expected.
Now, Is there a way to create a directory relative to the binary_dir specified in add_subdirecoty command?.
Note: The included subdirectory is a portable module so directory creation command should reside in its CMakeLists.txt file, not inside the root's CMakeLists.txt
there's CMAKE_CURRENT_BINARY_DIR variable. You may use it in expressions in CMake commands

CMake: adding custom resources to build directory

I am making a small program which requires an image file foo.bmp to run
so i can compile the program but to run it, i have to copy foo.bmp to 'build' subdirectory manually
what command should i use in CMakeLists.txt to automatically add foo.bmp to build subdirectory as the program compiles?
In case of this might help, I tried another solution using file command. There is the option COPY that simply copy a file or directory from source to dest.
Like this:
FILE(COPY yourImg.png DESTINATION "${CMAKE_BINARY_DIR}")
Relative path also works for destination (You can simply use . for instance)
Doc reference: https://cmake.org/cmake/help/v3.0/command/file.html
To do that you should use add_custom_command to generate build rules for file you needs in the build directory. Then add dependencies from your targets to those files: CMake only build something if it's needed by a target.
You should also make sure to only copy files if you're not building from the source directory.
Something like this:
project(foo)
cmake_minimum_required(VERSION 2.8)
# we don't want to copy if we're building in the source dir
if (NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
# list of files for which we add a copy rule
set(data_SHADOW yourimg.png)
foreach(item IN LISTS data_SHADOW)
message(STATUS ${item})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${item}"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${item}" "${CMAKE_CURRENT_BINARY_DIR}/${item}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${item}"
)
endforeach()
endif()
# files are only copied if a target depends on them
add_custom_target(data-target ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/yourimg.png")
In this case I'm using a "ALL" custom target with a dependency on the yourimg.png file to force the copy, but you can also add dependency from one of your existing targets.

How do I make build rules in cmake to preprocess lazy C++ .lzz files that generate .h and .cpp files?

What I'd like to do is write just Lazy C++ .lzz files and then have lzz run before a build to generate .cpp and .h files that will be built into the final application, sort of like how moc works with Qt.
Is there any way to do this?
Here is an example of how to do this... First you need to find the lzz program, for that use the find_program command:
find_program(LZZ_COMMAND lzz)
This sets LZZ_COMMAND to the path of the compiler. Then use a CMake custom command to compile the LZZ file to their C++ header/implementation files:
add_custom_command(
OUTPUT ${output}
COMMAND ${LZZ_COMMAND} -o ${CMAKE_CURRENT_BINARY_DIR} ${filename})
That generates the files in the current build directory, in case you do out-of-source builds. You will also need to specify that the outputs are generated files:
set_source_files_properties(${output} PROPERTIES GENERATED TRUE)
Put that all together and you get a CMakeLists.txt file something like this:
cmake_minimum_required(VERSION 2.8)
project(lazy_test)
find_program(LZZ_COMMAND lzz)
function(lazy_compile filename)
get_filename_component(base ${filename} NAME_WE)
set(base_abs ${CMAKE_CURRENT_BINARY_DIR}/${base})
set(output ${base_abs}.cpp ${base_abs}.h)
add_custom_command(
OUTPUT ${output}
COMMAND ${LZZ_COMMAND} -o ${CMAKE_CURRENT_BINARY_DIR} ${filename})
set_source_files_properties(${output} PROPERTIES GENERATED TRUE)
endfunction()
lazy_compile(${CMAKE_CURRENT_SOURCE_DIR}/example.lzz)
add_executable(test example.cpp example.h)
You would probably also want to add include path and other options to lzz eventually. If you placed all the Lazy C++ stuff into a module file and included that from the CMakeLists.txt it would be a bit cleaner. But this is the basic idea.
I just wanted to share my CMakeLists.txt, which builds upon richq's script. The *.cpp and *.hpp files now properly depend on the *.lzz files. The *.lzz files are added to the project (which answers absense's question above) but kept separate from the generated files using the source_group command.
The only remaining dealbreaker for me is the inability to compile the current file for *.lzz files.
cmake_minimum_required(VERSION 2.8)
PROJECT(LzzTest)
find_program(LZZ_COMMAND lzz.exe)
# Syntax:
# add_lzz_file(<output> <lzz file>)
# Adds a build rule for the specified lzz file. The absolute paths of the generated
# files are added to the <output> list. The files are generated in the binary dir.
#
# TODO: Support for generating template files etc.
function(add_lzz_file output filename)
# Only process *.lzz files
get_filename_component(ext ${filename} EXT)
if(NOT ext STREQUAL ".lzz")
return()
endif()
set(header_extension "hpp")
get_filename_component(base ${filename} NAME_WE)
set(base_abs ${CMAKE_CURRENT_BINARY_DIR}/${base})
set(outfiles ${base_abs}.cpp ${base_abs}.${header_extension})
set(${output} ${${output}} ${outfiles} PARENT_SCOPE)
#message("outfiles=${outfiles}, DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${filename}")
add_custom_command(
OUTPUT ${outfiles}
COMMAND ${LZZ_COMMAND}
-o ${CMAKE_CURRENT_BINARY_DIR} # output dir
-hx ${header_extension}
-sl -hl -il -tl -nl -x # insert #line commands w/ absolute paths
-sd -hd -id -td -nd # don't output files that didn't change
${CMAKE_CURRENT_SOURCE_DIR}/${filename}
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${filename}"
)
set_source_files_properties(${outfiles} PROPERTIES GENERATED TRUE)
endfunction()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(SOURCES
A.lzz
B.lzz
main.cpp
)
foreach(file ${SOURCES})
add_lzz_file(GENERATED_SOURCES ${file})
endforeach()
source_group("" FILES ${SOURCES})
source_group(generated FILES ${GENERATED_SOURCES})
add_executable(LzzTest ${SOURCES} ${GENERATED_SOURCES})
For make:
sourcecode.h sourcecode.cpp: sourcecode.lzz
<TAB>lazy-cpp sourcecode.lzz
fill in sourcecode.h, sourcecode.cpp, and lazy-cpp with the correct values. I don't know them.