Prefix all sources with src/ in Meson - meson-build

Relative to my project root where meson.build is located, all of my source files are under src/.
Is it possible to specify these source files in meson.build in a way that wouldn't force me to prefix them all with src/, given that that's somewhat redundant?

Prefixing source files shouldn't be needed because meson provides special function: files() which generates file array object that "remembers" subdirectory. For example, in the root meson.build you can have:
subdir('src')
subdir('src_more')
exe = executable('test', sources)
In src/meson.build:
sources = files('a1.c', 'a2.c')
And in src_more/meson.build:
sources += files('b1.c', 'b2.c')

You really should put a meson.build file in src/ and create the list there.

You can actually "build" an array of files using foreach statement:
raw_sources = [
'foo.cpp',
'foomanager.cpp',
'foofactory.cpp'
]
sources = []
foreach file : raw_sources
full_path = join_paths('src', file)
sources += files(full_path)
endforeach
And now sources contains files with the desired prefix.

Related

why Cmake's " file(REMOVE_RECURSE [file1 ...]) "does not remove file having *.xxx.yy extension file?

I want to remove all the files from my binary directory which has ".asm.js" extension
below is my source code
file (REMOVE
${CMAKE_BINARY_DIR}/dist/*.asm.js
)
Unfortunately, It's not able to delete the file which has .asm.js extension.
is there anyone who can help me with this
Thanks in advance
As CMake docs says :
Remove the given files. The REMOVE_RECURSE mode will remove the given
files and directories, also non-empty directories. No error is emitted
if a given file does not exist.
So you need to do a list of files to send it to file(REMOVE)
To do it you can use :
file(GLOB MY_FILES ${CMAKE_BINARY_DIR}/dist/*.asm.js)
Or if you want to match them in subdirectories :
file(GLOB_RECURSE MY_FILES ${CMAKE_BINARY_DIR}/dist/*.asm.js)
Then you can use your command :
file (REMOVE
${MY_FILES}
)
if you want to delete all the "asm.js" type of files in the subdirectory as well then you can use the below command
file(GLOB_RECURSE MY_FILES ${CMAKE_BINARY_DIR}/dist/**/*.asm.js)

CMake: install(FILES ...) for a file containing a list of files

Consider I have a simple text file containing a list of (absolute) file paths.
Is there any easy way to make CMake install those files (as if install(FILES ...) was used)?
Directory structure (minus some constant leading path components) should be maintained.
Right now the only option I could come up with was to use
install(CODE "execute_process(COMMAND my_script.sh)")
and do it using normal shell commands, but that seems to defeat the purpose of using a build system in the first place...
I believe this would do the trick:
# 'filename' is the file that contains a list ';' separated paths relative to that input file
function(install_my_files filename)
file(READ ${filename} relative_paths)
get_filename_component(parent_directory ${filename} DIRECTORY) # parent directory of input file
foreach(relative_path ${relative_paths})
get_filename_component(relative_directory ${relative_path} DIRECTORY)
install(FILES "${parent_directory}/${relative_path}" DESTINATION ${relative_directory})
endforeach()
endfunction()

Avoid repeating the directory name for multiple file inclusions

I have a CMakeLists.txt file for a library. It's pretty basic:
set(LIB_FILES source/first.cpp)
add_library(first ${LIB_FILES})
I put the files in a list because I will eventually be adding more source files to the library. The problem is that all of the files will be in the source directory. And I don't want to constantly have to repeat that.
I also don't want to use the GLOB pattern matching solution, because I want to have to edit the CMakeLists.txt file when I add a new file. That way, my build will re-build the build solution, and new files will correctly appear (as I understand it. I'm still new with CMake).
I tried adding a CMakeLists.txt file into the source directory itself, just to build the LIB_FILES list. That didn't work out very well. Variables in CMake are file scoped. And even when I broke scoping (with PARENT_SCOPE), I still had to prefix each file with the directory. So that gained nothing.
I don't want to put the actual library definition in the source directory, as that will generate all the build files in the source directory. And I don't want that. Also, I will need to include headers that aren't in or under the source directory.
My directory structure looks like this:
libroot (where the project build files should go)
\-source (where the source code is)
\-include (where the headers that the user of the library includes go)
So how do I tell CMake that all of the source files come from the source directory, so that I don't have to constantly spell it out?
You could move the add_library call to your source/CMakeLists.txt also:
set(LIB_FILES first.cpp)
add_library(first ${LIB_FILES})
Then just use add_subdirectory in your top-level CMakeLists.txt:
add_subdirectory(source)
you could use a simple macro for that
macro(AddSrc dst_var basepath_var)
foreach(file ${ARGN})
list(APPEND ${dst_var} ${basepath_var}/${file})
endforeach()
endmacro()
set(MY_SRCFILES "")
AddSrc(MY_SRCFILES path/to/source
foo.cpp
bar.cpp
whatever.cpp
)

How can I install a hierarchy of files using CMake?

I've created a list of files using:
file(GLOB_RECURSE DEPLOY_FILES "${PROJECT_SOURCE_DIR}/install/*")
I want to install all of these files in /usr/myproject/, but I want to maintain the file tree on the installed folder:
install/junk
install/other/junk2
install/other/junk3
If I use:
install(FILES ${DEPLOY_FILES} DESTINATION "usr/myproject")
All the files end up in /usr/myproject as:
/usr/myproject/junk
/usr/myproject/junk2
/usr/myproject/junk3
How can I make the install command keep track of relative paths?
I've worked around the issue by doing it manually in a for loop:
set(BASE "${PROJECT_SOURCE_DIR}/install")
foreach(ITEM ${DEPLOY_FILES})
get_filename_component(ITEM_PATH ${ITEM} PATH)
string(REPLACE ${BASE} "" ITEM_PATH ${ITEM_PATH})
install(FILES ${ITEM} DESTINATION "usr/myproject${ITEM_PATH}")
endforeach()
...but this is annoying to do. Surely there's an easier way?
(I can't see anything in the install documentation though...)
The simplest way to install everything from a given directory is:
install(DIRECTORY mydir/ DESTINATION dir/newname)
Trailing '/' is significant.
Without it mydir would be installed to newname/mydir.
From the CMake documentation:
The last component of each directory name is appended to the destination
directory but a trailing slash may be used to avoid this because it
leaves the last component empty.
I am assuming you have a list of files, let's say INCLUDE_FILES. Possibly a selection of files spread over a number of subdirectories, e.g. header files from across the source tree, as opposed to everything in a single subdir like in the other answers.
You can loop over the file list and use get_filename_component() to extract the directory part, then use that in a subsequent install() to set the DESTINATION subdirectory:
foreach ( file ${INCLUDE_FILES} )
get_filename_component( dir ${file} DIRECTORY )
install( FILES ${file} DESTINATION include/${dir} )
endforeach()
Done. ;-)
Edit: If all the files you want to install that way match a particular file pattern -- e.g. "all header files" -- then brno's answer has the edge over this one.
Use:
INSTALL( DIRECTORY <directory> DESTINATION usr/myproject )
(See here for details: http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:install)
INSTALL( DIRECTORY ... ) preserves the directory structure. But, if you use install as <directory>, you would end up with usr/myproject/install/.... which is not what you want.
There are two ways to do this:
Use INSTALL( FILES .... DESTINATION usr/myproject) to install the files that lie directly in install/, then use INSTALL( DIRECTORY .... DESTINATION usr/myproject) and manually list the directories to install.
Use your globbing command in your original post, and then determine which entries are files, which are directories, move the directory entries to a separate list, feed the lists to INSTALL( FILES ...) and INSTALL( DIRECTORY ...), respectively.
file(GLOB DEPLOY_FILES_AND_DIRS "${PROJECT_SOURCE_DIR}/install/*")
foreach(ITEM ${DEPLOY_FILES_AND_DIRS})
IF( IS_DIRECTORY "${ITEM}" )
LIST( APPEND DIRS_TO_DEPLOY "${ITEM}" )
ELSE()
LIST( APPEND FILES_TO_DEPLOY "${ITEM}" )
ENDIF()
endforeach()
INSTALL( FILES ${FILES_TO_DEPLOY} DESTINATION usr/myproject )
INSTALL( DIRECTORY ${DIRS_TO_DEPLOY} DESTINATION usr/myproject )
Note: Depending on the type of files you install, other INSTALL( ...) commands might be more appropriate (for example, INSTALL( TARGETS .... ) to install your libraries/executables.
Since globbing is not recommended, and running loops in CMakeLists.txt files is clunky, a pattern matching option of DIRECTORY did the trick for me.
install(DIRECTORY src/ DESTINATION include FILES_MATCHING PATTERN "*.h")
This took the entire folder structure inside src/ and reproduced it within <INSTALL_DIR>/include, header files only.

Where to put the binary in CMake?

in my project, all source code resides in a folder named "src". There's a CMakeLists.txt file in my projects root (above "src"), but it merely declares the project and includes the "src" subdirectory. The CMakeLists.txt file under src does all the work, including "add_binary".
(Is that a common way of doing it, or should I put all the intelligence in the CMakeLists.txt file at the root level?)
If I build the project now, my binary is placed into the src folder, but this doesn't make a lot of sense, I'd rather have it in the root folder or a dedicated "bin" folder.
How do you do this?
If you want to put all your executable files in a subdirectory called "bin", then you can use the following line in the top CMakeLists.txt file:
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
Just remove /bin and executables will be created in the root directory. A similar variable exists for libraries: CMAKE_LIBRARY_OUTPUT_DIRECTORY.
PS. Adding per-directory logic is fine. It seems to be the common way to do things and keeps things nicely organized.