Change lib's sources depending on conditional requirements in a factorized way using boost build/b2/bjam - conditional-statements

I have a lib target that needs different (additional) libraries on some OSes.
I would like to do something like:
lib MyLib : $(SOURCES) $(COMMON_LIBS) <target-os>windows:$(WINDOWS_LIBS) ;
but that returns error: properties found in the 'sources' parameter for ./MyLib I think it's because you cannot uses conditional properties there.
Or maybe using alternatives:
lib MyLib : $(SOURCES) $(COMMON_LIBS) ;
lib MyLib : $(SOURCES) $(COMMON_LIBS) $(WINDOWS_LIBS)
: <target-os>windows
;
well that would works but with a lot of redundancy (and this example is not that complex) and I would like to factorize it.
How to factorize this ?

Try to use alias:
alias os_libs : $(WINDOWS_LIBS) : requirements <target-os>windows ;
alias os_libs : ; # no additional libs for other OSes
lib MyLib : $(SOURCES) $(COMMON_LIBS) os_libs ;

Related

How to include target include directories transitive through multiple linked libraries

we are working on an embedded project in C/C++ and currently some special needs appeared. Background is there are two compiled libraries which define the same symbols. The compiler allows to create relocatable output modules (with partial linking) and to hide symbols for other compilation units when linking. This also means the output module does not need to have all the symbols defined, this will be done in the final linking. Compiler used is TI LTS1.3.0. I will link directly to the relocatable-section of the manual: https://software-dl.ti.com/codegen/docs/tiarmclang/rel1_3_0_LTS/compiler_manual/linker_description/04_linker_options/linker-output-options.html#stdz0756429
The other part of the project is hardly built on CMake with static libraries which are linked against each other via target_link_libraries.
To get this working I created an "add_executable"-target for each of those both output modules with the same symbols. To those I pass the static-libraries by CMake and get the linked with target_link_libraries.
But now I have a problem. All contents of the static libraries are compiled in each of those output modules. This is unwanted behaviour since as said the final linking does the job of linking the missing stuff - so the static-libraries - to it. This should be done with another add_executable command via CMake as well.
using the target include directories property is not suitable since it only adds the include directories of the given target itself but not of the target the target will include and link against.
So e.g. if you have (pseudo code):
#library A
function( create_libA )
add_library( libA src/A.c )
target_include_directories( libA PUBLIC /inc ) #contains A.h
endfunction()
#library B. different location
function( create_libB LIBA )
add_library( libB src/B.c )
target_link_libraries( libB PUBLIC ${LIBA} )
target_include_directories( libB PUBLIC /inc ) #contains B.h
endfunction()
#target output module with partial linking. Only should link and compile LIBTOBELINKEDIN, not libB. different location.
function( build_part_module LIBB LIBTOBELINKEDIN )
add_executable( outputModuleA src/func.c ) #func.c does include A.h
#following would cause libA and libB also to be compiled and linked in the output due to transitive stuff as I understood, which is unwanted.
target_link_libraries( outputModuleA PUBLIC ${LIBB} ${LIBTOBELINKEDIN} )
#trying this
get_target_property(libBInc ${LIBB} INTERFACE_INCLUDE_DIRECTORIES)
#will only include B.h but not A.h. compilation will fail.
target_include_directories(outputModuleA /inc ${libBInc})
I did not find any solution in Cmake itself to solve this problem. It's confusing me since all the include-directories must be known when the libraries are passed transitive, which is stated in the documentation. But I understand that getting the target include directories of just the passed lib does not include the other ones.
Since target_link_libraries does also not work this way I can only think of a maybe recursive solution? But for that my knowledge is just non-existent.
target_link_libraries with something like HEADERS_ONLY would be helpfull for this job.
Also one can say: if the output module contains all the definitions it won't be a problem, since the linker then knows them and will do its magic.
But this is also unwanted, since we use the generated static-libraries to place them into sections in different regions of the RAM directly. This would then mean to create another linker-script for partial linking which defines sections which then can be again moved. But the more we go this direction, the less we need CMake for it.
Instead of get_target_property use $<TARGET_PROPERTY> generator expression: the property's value, extracted by that expression, already includes transitive propagation:
target_include_directories(outputModuleA PRIVATE
$<TARGET_PROPERTY:libB,INTERFACE_INCLUDE_DIRECTORIES>
)
Note, that generator expressions has limited usage: not all functions expects them. Documentation for target_include_directories clearly states that the command supports generator expressions.

is it possible to make target shared library file name variable according to environment variable in cmake?

I'm not familar with cmake but in CMakeLists.txt we set the target shared library name like this.
add_library( mylib SHARED ${source_list} )
This generates libmylib.so and other settings in CMakeLists.txt are defined for mylib like
about the mylib
and also we can use shell environment variable to do some selective settings like
target_compile_definitions( mylib PRIVATE -DQQQ -D... )
Also it is possible to use shell environment variable to do some selective things.
if(defined env{MYVAR})
set(CMAKE_C_FLAGS "-g -DXYZ")
else()
set(CMAKE_C_FLAGS "-DXYZ")
endif()
I would be happy if I could set the target shared library name as a variable according to the environment variable and use that selected name variable as the shared library name in all other settings. In other words, is it possible to do things like below?
if (defined ENV{FOR_QEMU})
set_name(target_name "simlib_qemu")
else ()
set_name(target_name "simlib")
endif ()
add_library(target_name SHARED ${source_list} )
target_compile_definitions( target_name PRIVATE -DQQQ -D... )
...
You can set the output name of a target to anything you like via:
set_target_properties(target_name PROPERTIES OUTPUT_NAME "whatever")
Then instead of libtarget_name.so, you'll get libwhatever.so. You would continue to refer to the target as target_name in your CMakeLists.txt.
However, since this will only work during configure time anyway, I strongly urge you to use a normal CMake variable instead. You may initialize it from the environment if it is not set, like so:
option(FOR_QEMU "Enable if building with Qemu support" "$ENV{FOR_QEMU}")
add_library(simlib SHARED ${source_list})
target_compile_definitions(simlib PRIVATE -DQQQ -D...)
if (FOR_QEMU)
set_target_properties(target_name PROPERTIES OUTPUT_NAME "simlib_qemu")
endif ()
This way, the CMake variable FOR_QEMU is the de-facto control and it is initialized on the first execution if the matching env-var is set. It will also appear with documentation in the cache, so other developers may query the build system directly for all its configuration points. Bear in mind: CMake is not Make and reading from the environment on every configure is a surprising behavior and generally bad practice.

How do I access a module's symbol table dynamically at runtime in Raku?

I want to be able to pass my script the path to a .rakumod file, say <blah>/Mod.rakumod, and be able to access the symbol table as a hash as if I'd used the module instead:
The module:
$ cat Mod.rakumod
unit module Mod;
sub bag is export { ... }
use lib <dir-containing-Mod>
use Mod;
say Mod::EXPORT::.keys
works, as expected, returning (ALL DEFAULT).
On the other hand:
use lib <dir-containing-Mod>
require Mod;
say Mod::EXPORT::.keys
fails with
Could not find symbol '&EXPORT' in 'Mod'
in block <unit> at <blah>
This is despite the fact that even with require, say Mod::.keys does see EXPORT:
use lib <dir-containing-Mod>
require Mod;
say Mod::.keys
---
(EXPORT Mod)
I need to use require to make this dynamic, as I don't know which module I'll want.
I can actually think of one thing to do, but it is absolutely disgusting:
save my module name into a variable $mod
have my script write another script using that module:
my $mod = <whatever>
my $cd = qq:to/END/;
use v6;
use lib qq\|\$\*CWD\|;
use $mod;
say {$mod}::EXPORT::ALL::.keys;
END
'aux.p6'.IO.spurt($cd);
and then have the initial script call the auxiliary one:
shell("raku aux.p6")
What worked, per raiph's answer (which I've accepted and am here paraphrasing):
pass the path to the module and save it as $path;
use lib the relevant directory:
my $dir = $path.IO.dirname;
use lib $dir;
extract the plain file name:
my $modFile = S/(.*)\..*/$0/ with $path.IO.basename;
finally, require that and pull the .WHO trick from raiph's answer, slightly adapted:
require ::($modFile);
say ::("{$modFile}::EXPORT::ALL").WHO.keys;
Run with <script> <path> that returned (&bag) all right.
Actually, the above doesn't quite work: use lib $dir will fail saying $dir is empty, because use lib isn't dynamic.
So instead I am now resorting to the unappealing solution of
copying the module file to a temporary directory ./TMP
having called use './TMP';
and then removing that directory when done.
TL;DR Use dynamic symbol lookup to get the symbol of the package whose symbols you want at run-time; then .WHO to get its stash; then .keys to get that stash's symbols.
For example:
use lib '.';
require Mod;
say ::Mod::EXPORT::('ALL').WHO.keys; # (&bag)
I'm going to make breakfast. I'll elaborate later.

Perl6 generic code to test if modules load

This is a generic code code in /t to test if .pm6 modules in /lib load.
use lib $*PROGRAM.sibling('../lib');
use Test;
my #dir = dir($*PROGRAM.sibling('../lib'), test => { $_ ~~ /.*pm6/ } );
plan #dir.elems;
sub module( IO $dir ) {
$dir.basename.Str ~~ /(\w+)\.pm6/;
return $0.Str;
}
for #dir.map(&module) -> $module {
use-ok $module, "This module loads: $module";
}
Before going any further (recursively looking at lib sub-folders ), I wonder in this is the right approach.
Thanks!
If you are testing a well-formed distribution then you should be using:
use lib $*PROGRAM.parent(2);
By pointing use lib at the directory containing your META6.json instead of the lib directory you help ensure that the provides entry of the META6.json file is up to date (since files not listed in the META6.json but that do exist inside lib won't be seen).
(I'd even take it one step further and say don't use use lib '...' at all, and instead run your tests using perl6 -I .... For instance -- what if you want to run these tests (for whatever reason) on the installed copy of some distribution?)
With that said you could skip the directory recursion by using the META6 data. One method would be to read the META6.json directly, but a better way of doing so would be to get the module names from the distribution itself:
# file: zef/t/my-test.t
# cwd: zef/
use lib $*PROGRAM.parent(2); # or better: perl6 -I. t/my-test.t
use Test;
my $known-module = CompUnit::DependencySpecification.new(short-name => "Zef");
my $comp-unit = $*REPO.resolve($known-module);
my #module-names = $comp-unit.distribution.meta<provides>.keys;
use-ok($_) for #module-names;
Using #ugexe feedback and META6 distribution, the following code in t/ tests that modules defined in META6.json load.
use META6;
use Test;
my $m = META6.new( file => $*PROGRAM.sibling('../META6.json') );
my #modules = $m<provides>.keys;
plan #modules.elems;
for $m<provides>.keys -> $module {
use-ok $module, "This module loads: $module";
}
This test has been pulled into the META6 distribution.

How can I find a library name of .so file?

For example, I have libprofiler.so file. How can I get name of this shared object like this:
getname /usr/lib/libprofiler.so
I want to do it because it is required for CMakeLists.txt in
target_link_libraries(MyProject name_of_library)
Do the following steps to link an existing lib to your target:
Inform you which lib do you need: here profiler.
Build the name of the lib. CMake does not really needs this but it is worth to know: Example on Unix/Linux lib + NAME + [.so|.a] [VERSION]. Here: libprofiler.so.
In your CMakeLists.txt:
find_library(LIB_PROFILER NAMES profiler libprofiler.so libprofiler.so.V123)
add_executable(MyApp ${SOURCES})
target_link_libraries(MyApp ${LIB_PROFILER})
The code above tries to find a lib and checks the following name profiler, libprofiler.so and libprofiler.so.V123. If found, the variable LIB_PROFILER points to the lib file.
Use the variable as one of the files linked to your target.
In your code, you also missed the ${} around the variable.