meson: use library before declaring it - meson-build

Lets say your project looks like this:
meson.build:
project('myproject', 'cpp')
subdir('a')
subdir('b')
subdir('c')
a/meson.build:
mylib_a = library('mylib.cpp')
executable('a', 'main.cpp', link_with : [mylib_a])
with b/meson.build and c/meson.build looking similar.
If you would want to link the 'c' executable against mylib_a or mylib_b, you can simply add them to the array. But if you would want to link the 'a' executable against mylib_b or mylib_c you cannot do this without reordering the "subdir" commands. And If you would want to link 'c' against 'mylib_a' and 'a' against 'mylib_c', the only way, I could make it work is by putting the "executable('a', 'main.cpp', link_with : [mylib_a])" commands into meson.build instead of a/meson.build. This screws up the directory structure.
Is there any way I could link 'a' against mylib_c and 'c' against mylib_a without screwing up my directory structure?
UPDATE:
The meson authors say that there is no way to do this, but they will add one soon:
https://github.com/mesonbuild/meson/issues/8178

You can try placing all executable's in the bottom of the root meson.build file. In this case all mylib_a/b/c variables will be available. You will also need to create in each subdirectory meson.build file file_a/b/c variables, e.g.
file_a = files('main.cpp')
and use them in corresponding executable(...).
This may suffice your needs, but I suggest you to look towards using subprojects concept instead.
UPDATE
To avoid clutter if you have many sub-directories, libraries and executables you can use loop with foreach:
libs = ['a', 'b', 'c']
lib_list = []
foreach l : libs
lib_list += library(l, join_paths(l, 'mylib.cpp'))
endforeach
progs = ['a', 'b', 'c']
foreach p : progs
exe = executable(p, join_paths(p, 'main.cpp'), link_with : lib_list)
endforeach

Related

How do I derive an executable name from a source file in Meson build?

I'm trying to create a list of unit test targets in Meson, with each test case built from a single source file. The source files are defined with a files() command in a subdirectory:
my_test_files = files(['test_foo.c','test_bar.c','test_baz.c'])
What I'd like to do is something like this in the top-level build:
foreach t_file : my_test_files
t_name = t.split('.')[0]
test(t_name, executable(t_name, t_file, ...))
endforeach
I know it's possible to do this if the file names are plain strings, but the above approach fails with a 'File object is not callable' error.
Is there a more 'Mesonic' way to derive the executable / test name from the source file name?
It should work if you define your variable simply as array, e.g.:
my_test_files = ['test_foo.c','test_bar.c','test_baz.c']
the loop stays the same, except some typo fixed with:
foreach t_file : my_test_files
t_name = t_file.split('.')[0]
test(t_name, executable(t_name, t_file, ...))
endforeach
instead of building array of file objects. This is because executable() accepts input files in many forms: as file objects (which you tried to do) and as strings either source files (that should be compiled) or object files (to be linked) - detected by file name extension.
For more flexibility and better control, one can use array of arrays (which is, of course, extendable and may contain anything that is needed to generate tests):
foo_files = files('test_foo.c')
bar_files = files('test_bar.c')
baz_files = files('test_baz.c')
test_files = [
['foo', foo_files, foo_deps],
['bar', bar_files, []],
['baz', baz_files, baz_deps]]
foreach t : test_files
test(t[0], executable(t[0], t[1], dependencies=t[2], ...))
endforeach

CMakeLists using variables to define source/include locations

I have an AndroidStudio project with 'C' files in. I can compile and run as-is.
My native files are in
src/main/jni/aes
src/main/jni/libjpeg
src/main/jni/smuglib
I am trying to move the source to a location external to the Android studio project so that I can use it from several locations/projects to avoid copy/paste/mistake cycle.
I have defined the include path in CMakeLists.txt
include_directories(src/main/jni/aes src/main/jni/libjpeg src/main/jni/smuglib)
And have specified the files in the add_library command
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/jni/aes/aes.c
src/main/jni/smuglib/smuglib.c
.... etc
How do I set up a variable to refer to these paths, eg 'src/main/jni/aes' so that I can use it in both the include and in the source list?
I tried variations on
set(aes_src, src/main/jni/aes)
but uses of it as ${aes_src} either in the include path statement or in the source list give me all sorts of arcane errors which I am at a loss to understand.
I will generate some of these and include them if folk think it would help, but I am likely barking up the wrong kettle of fish with this approach.
Is there a better approach?
It is set(VAR_NAME item1 item2 item3). No commas needed.

How can I concatenate multiple files into one in Meson?

I'm having trouble with a basic task in Meson where I need multiple files concatenated into one during build; basically:
cat *.txt > compiled.txt
or
cat foo.txt bar.txt baz.txt > compiled.txt
However whether I use custom_target(), generator() or any other function, Meson either can't find the compiled.txt or can't handle transitioning from multiple input files to a single output file.
Is there an easy way to achieve this?
Update:
Using run_command() I've managed to build compiled.txt and have it appear in the source directory. Ultimately I want compiled.txt (which I've listed in the gresource.xml) to be compiled by gnome.compile_resources(). Is there a way I can run this command and pass the file directly to that function to process?
Use custom_target(), pass the output to dependencies of gnome.compile_resources(). Note you will need a fairly recent glib for it to work.
See also: http://mesonbuild.com/Gnome-module.html#gnomecompile_resources
Moved solution from question to answer:
Solution:
I ended up not using gresources, but still needed this solution to concatenate files
cat_prog = find_program('cat')
parts_of_the_whole = files(
'part1.txt',
'part2.txt'
)
concat_parts = custom_target(
'concat-parts',
command: [ cat_prog, '#INPUT#' ],
capture: true,
input: parts_of_the_whole,
output: 'compiled.txt',
install_dir: appdatadir,
install: true,
build_by_default: true
)

CMake: Managing a list of source files

The problem I'm having at the moment is that I simply wish to manage my list of source files by grabbing everything and removing the few odds and ends that I do not need. I was hoping that Cmake provided nice built-in tools for this.
So I might start with:
file(GLOB A "Application/*.cpp")
I feel like I want to create another list of files to be removed and I want to tell CMake: Remove from list A items that are in list B.
If this were Python I might do something like:
C = [f for f in A if f not in B]
I may have screwed that syntax up but I'm wondering if there is built-in support for managing these lists of files in a more elegant way?
Even if I could do something like my Python example, A is list of absolute paths so constructing B is clunky.
And why absolute paths anyway? It seems like this will break your build as soon as you relocate the source.
You can do that by using the list command with the REMOVE_ITEM option:
list(REMOVE_ITEM <list> <value> [<value> ...])
Have a look:
file(GLOB FOO *)
set (ITEMS_TO_REMOVE "item;item2;item3")
message(STATUS "FOO is ${FOO}")
list(REMOVE_ITEM FOO ${ITEMS_TO_REMOVE})
message(STATUS "FOO is now ${FOO}")
Keep in mind that the paths returned by file(GLOB) are absolute, you might want to build your list of items to remove by prepending ${CMAKE_CURRENT_LIST_DIR} to each one of them:
set (ITEMS_TO_REMOVE "${CMAKE_CURRENT_LIST_DIR}/item;
${CMAKE_CURRENT_LIST_DIR}/item2;
${CMAKE_CURRENT_LIST_DIR}/item3")
If you like Python, you can generate your list of source files with execute_process. There is also possiblity to work with lists.
But I would recommend you to "hardcode" your list of source files.
File command documentation states:
We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.

CMake: collecting libraries

I am using CMake to build a simple C++ project, hereafter named P. The structure of P is quite simple:
P/src/
P/src/package1
P/src/packege2
P/src/...
P/src/main-app
I would like to collect the libraries in package1, package2, ... in a variable called P_LIBS.
In a first attempt, I tried to collect the libraries available in package1, package2, ... in the variable called P_LIBS initially set in the src/CMakeLists.txt file. However, the updates to P_LIBS made in the CMakeLists.txt of the subfolders are not propagated to the parent folder.
I would rather not write a list of libraries in the main CMakeLists.txt file. I would rather modify such variable while moving in the directory tree.
After a search on the internet I could not find any valid suggestion. If I look at the various Find files, I only see long listings of libraries in their main CMakeLists.txt file.
Is there a way to do what (I hope) I explained above?
Thanks to sakra's link I was able to 'propagate' names up to the parent folder. However, the names I add to the P_LIBS variable are later interpreted as 'library' names, not as reference to CMake targets. In other words, if
P_LIBS = {a, b}
the 'a' and 'b' are interpreted as the library names, i.e. CMake generates:
gcc [...] -l a -o exe
instead of
gcc [...] /path/to/a.o -o exe
(.o or other extensions)
You are propably constructing the targets list as a string, try to make them a list instead. For example:
# in package1/CMakeLists.txt
set(P_LIBS ${P_LIBS} a b PARENT_SCOPE)