libtool: what is the path to my module? - automake

I am creating a module from an autotools+libtool project:
The Makefile.am looks as follows
#the module:
lib_LTLIBRARIES = mmmm.la
mmmm_la_SOURCES = mmmm.c
mmmm_la_LDFLAGS = $(AM_LDFLAGS) -module -shared
Now, I want to write a C test for my module. The test should start loading the shared object mmmm.xx (where .xx is .so or .la)
What path should I give to dlopen() or lt_dlopen() in my C test?: The relative location of my module (compared to the test program) is different depending on whether I do make check, an out of tree make check, or a make installcheck...
I tried with lt_dlopen() hoping that the -dlopen option passed on the test Makefile.am would help autotools to locate the lib when lt_dlopen() is called, but it does not seem to help: lt_dlopen() can open the .la file, indeed, but one still have to tell where that file is located (possibly ommiting the .libs directory)
My test makefile looks like this when testing with the ltdl lib:
#the module test (tests are also installed, hence the "test" prefix)
test_PROGRAMS = tttt
tttt_SOURCES = tttt.c
tttt_LDADD = "-dlopen" mmmm.la
tttt_DEPENDENCIES = mmmm.la
Any good hint?

One way you can deal with that is to set up the LD_LIBRARY_PATH env variable to where your library will be installed.
However, since you need it for the tests I will say export a variable from the configure.ac to the config.h. Thus, any file including the config.h would have a #define your_variable which can be used to set up the path for dlopen.

Related

Makefile.am: How to link a dynamic library only if the library exists/is installed on the system

I have a dynamic library /usr/lib64/liba-3.2.so.1. And, I am trying to change Makefile.am so that myprog_LDADD can link against this library if the file exists. Is there any way to do it?
I tried this:
if [ -f /usr/lib64/liba-3.2.so.1 ]; then myprog_LDADD += /usr/lib64/liba-3.2.so.1 ; fi;
But this is not working. Any suggestions on how to make Makefile.am link against a library if the library exists? Thanks!
the usual way would of course be to use your configure(.ac) (autotools) to check for the existance of a library and then use the the result to tell your Makefile(.am) to link against the library.
Snippet from configure.ac:
AC_CHECK_LIB([a-3.2], [a_fun], [A_LIBS="-la-3.2"])
AC_SUBST([A_LIBS])
and the corresponding snippet from Makefile.am:
myprog_LDADD += #A_LIBS#
Note that this will look for liba-3.2.so in all the (default) search paths of the linker, and without the .1 suffix, but I think this is the correct behavior anyhow (and you explicit linking against /usr/lib64/liba-3.2.so.1 is bound to fail in multiple scenarios starting with non-64bit platforms, so I'd consider this over-adaption)

How to correctly link the path of external library in CMake? [duplicate]

How to get CMake to link an executable to an external shared library that is not build within the same CMake project?
Just doing target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so) gives the error
make[2]: *** No rule to make target `res/mylib.so', needed by `GLBall'. Stop.
make[1]: *** [CMakeFiles/GLBall.dir/all] Error 2
make: *** [all] Error 2
(GLBall is the executable)
after I copied the library into the binary dir bin/res.
I tried using find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)
Which fails with RESULT-NOTFOUND.
arrowdodger's answer is correct and preferred on many occasions. I would simply like to add an alternative to his answer:
You could add an "imported" library target, instead of a link-directory. Something like:
# Your-external "mylib", add GLOBAL if the imported library is located in directories above the current.
add_library( mylib SHARED IMPORTED )
# You can define two import-locations: one for debug and one for release.
set_target_properties( mylib PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/res/mylib.so )
And then link as if this library was built by your project:
TARGET_LINK_LIBRARIES(GLBall mylib)
Such an approach would give you a little more flexibility: Take a look at the add_library( IMPORTED) command and the many target-properties related to imported libraries.
I do not know if this will solve your problem with "updated versions of libs".
Set libraries search path first:
link_directories(${CMAKE_BINARY_DIR}/res)
And then just do
target_link_libraries(GLBall mylib)
I assume you want to link to a library called foo, its filename is usually something link foo.dll or libfoo.so.
1. Find the library
You have to find the library. This is a good idea, even if you know the path to your library. CMake will error out if the library vanished or got a new name. This helps to spot error early and to make it clear to the user (may yourself) what causes a problem.
To find a library foo and store the path in FOO_LIB use
find_library(FOO_LIB foo)
CMake will figure out itself how the actual file name is. It checks the usual places like /usr/lib, /usr/lib64 and the paths in PATH.
You already know the location of your library. Add it to the CMAKE_PREFIX_PATH when you call CMake, then CMake will look for your library in the passed paths, too.
Sometimes you need to add hints or path suffixes, see the documentation for details:
https://cmake.org/cmake/help/latest/command/find_library.html
2. Link the library
From 1. you have the full library name in FOO_LIB. You use this to link the library to your target GLBall as in
target_link_libraries(GLBall PRIVATE "${FOO_LIB}")
You should add PRIVATE, PUBLIC, or INTERFACE after the target, cf. the documentation:
https://cmake.org/cmake/help/latest/command/target_link_libraries.html
If you don't add one of these visibility specifiers, it will either behave like PRIVATE or PUBLIC, depending on the CMake version and the policies set.
3. Add includes (This step might be not mandatory.)
If you also want to include header files, use find_path similar to find_library and search for a header file. Then add the include directory with target_include_directories similar to target_link_libraries.
Documentation:
https://cmake.org/cmake/help/latest/command/find_path.html
and
https://cmake.org/cmake/help/latest/command/target_include_directories.html
If available for the external software, you can replace find_library and find_path by find_package.
Let's say you have an executable like:
add_executable(GLBall GLBall.cpp)
If the external library has headers, give the path to its include folder:
target_include_directories(GLBall PUBLIC "/path/to/include")
Add the library directory path:
target_link_directories(GLBall PUBLIC "/path/to/lib/directory")
Finally, link the library name
target_link_libraries(GLBall mylib)
Note that the prefix and extension of the library file are removed:
libmylib.a ➜ mylib
mylib.so ➜ mylib
One more alternative, in the case you are working with the Appstore, need "Entitlements" and as such need to link with an Apple-Framework.
For Entitlements to work (e.g. GameCenter) you need to have a "Link Binary with Libraries"-buildstep and then link with "GameKit.framework". CMake "injects" the libraries on a "low level" into the commandline, hence Xcode doesn't really know about it, and as such you will not get GameKit enabled in the Capabilities screen.
One way to use CMake and have a "Link with Binaries"-buildstep is to generate the xcodeproj with CMake, and then use 'sed' to 'search & replace' and add the GameKit in the way XCode likes it...
The script looks like this (for Xcode 6.3.1).
s#\/\* Begin PBXBuildFile section \*\/#\/\* Begin PBXBuildFile section \*\/\
26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks \*\/ = {isa = PBXBuildFile; fileRef = 26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/; };#g
s#\/\* Begin PBXFileReference section \*\/#\/\* Begin PBXFileReference section \*\/\
26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System\/Library\/Frameworks\/GameKit.framework; sourceTree = SDKROOT; };#g
s#\/\* End PBXFileReference section \*\/#\/\* End PBXFileReference section \*\/\
\
\/\* Begin PBXFrameworksBuildPhase section \*\/\
26B12A9F1C10543B00A9A2BA \/\* Frameworks \*\/ = {\
isa = PBXFrameworksBuildPhase;\
buildActionMask = 2147483647;\
files = (\
26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks xxx\*\/,\
);\
runOnlyForDeploymentPostprocessing = 0;\
};\
\/\* End PBXFrameworksBuildPhase section \*\/\
#g
s#\/\* CMake PostBuild Rules \*\/,#\/\* CMake PostBuild Rules \*\/,\
26B12A9F1C10543B00A9A2BA \/\* Frameworks xxx\*\/,#g
s#\/\* Products \*\/,#\/\* Products \*\/,\
26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/,#g
save this to "gamecenter.sed" and then "apply" it like this ( it changes your xcodeproj! )
sed -i.pbxprojbak -f gamecenter.sed myproject.xcodeproj/project.pbxproj
You might have to change the script-commands to fit your need.
Warning: it's likely to break with different Xcode-version as the project-format could change, the (hardcoded) unique number might not really by unique - and generally the solutions by other people are better - so unless you need to Support the Appstore + Entitlements (and automated builds), don't do this.
This is a CMake bug, see http://cmake.org/Bug/view.php?id=14185 and http://gitlab.kitware.com/cmake/cmake/issues/14185
It has been a long time since the question was posted but I am leaving this one just for reference.
I have a blog post describing step-by-step almost what you (or anyone else) were trying to do.
Please check here: https://michae9.wordpress.com/2022/09/01/shared-lib-to-be-used-by-client-programs-with-cmake/

How to link .cma files to my own Frama_C plugin?

I created my own Frama-C plugin by following the instructions of the Frama-C Development Guide (https://frama-c.com/download/frama-c-plugin-development-guide.pdf).
However, I need to use the Mutex module provided by the Ocaml manual (http://caml.inria.fr/pub/docs/manual-ocaml/libref/Mutex.html) in my .ml files. To use this module, I need a particular command line:
ocamlc -thread unix.cma threads.cma myfiles.ml
(as explained here: OCaml Mutex module cannot be found).
To compile my files I use the Makefile that builds the plugin (Plugin Development Guide page 33). So I'm trying to link these .cma files and the -thread option to this Makefile...and I did not succeed. How can I load this Mutex module?
What I tried:
I looked in the file automatically generated by Frama-C: .Makefile.plugin.generated if there was a variable to call and modify in my Makefile (the same kind as the variable PLUGIN_CMO to call my .ml files) but I did not find such a variable.
I tried with some variables that are defined in the generated .Makefile.plugin.generated this way:
I wrote the following lines in my Makefile:
PLUBIN_EXTRA_BYTE = unix.cma threads.cma
or TARGET_TOP_CMA = unix.cma threads.cma
and for the thread option:
PLUGIN_OFLAGS = -thread
or PLUGIN_LINK_BFLAGS= -thread
or PLUGIN_BFLAGS= -thread
But never was the Mutex module recognized and I don't know exactly if it is a good solution...
Finally, I tested using the Olddynlink module provided by Frama-C (http://arvidj.eu/frama/frama-c-Aluminium-20160501_api/frama-c-api/html/FCDynlink.OldDynlink.html#VALloadfile) with the value loadfile or using the Dynlink module (http://caml.inria.fr/pub/docs/manual-ocaml/libref/Dynlink.html#VALloadfile) and his value loadfile, but it did not work either:
I wrote:
open Dynlink
loadfile "unix.cma";;
loadfile "threads.cma";;
in the .ml file concerned.
But always the same error: Unbound module Mutex.
Section 5.2.3 of the plugin development guide gives the list of variables that can be used to customize the Makefile. Notably, if you want to link against an external library, you can use PLUGIN_EXTRA_BYTE and PLUGIN_EXTRA_OPT, as well as PLUGIN_LINK_BFLAGS and PLUGIN_LINK_OFLAGS to add the -thread option. Here is a Makefile that should work (of course, you need to complete it depending on your actual source files).
ifndef FRAMAC_SHARE
FRAMAC_SHARE:=$(shell frama-c-config -print-share-path)
endif
PLUGIN_NAME:=Test_mutex
PLUGIN_BFLAGS:=-thread
PLUGIN_OFLAGS:=-thread
PLUGIN_EXTRA_BYTE:=$(shell ocamlfind query threads)/threads/threads.cma
PLUGIN_EXTRA_OPT:=$(shell ocamlfind query threads)/threads/threads.cmxa
PLUGIN_LINK_BFLAGS:=-thread
PLUGIN_LINK_OFLAGS:=-thread
PLUGIN_CMO:= # list of modules of the plugin
include $(FRAMAC_SHARE)/Makefile.dynamic
Note that in theory, you should only have to use the PLUGIN_REQUIRES variable, and let ocamlfind take care of everything but threads seems to be a bit peculiar in this respect.

How do I generate loadable modules during Linux kernel build?

I seem to successfully build a kernel image, but I can not generate all the modules I expect. I expect more modules since I see them enabled in the gconfig window. Here is a copy of my make session. Seems like make goes into the devices directories. I can not figure out why it is not create the .ko files. I expect to see .ko files. I have checked the Makefile in /drivers directory, and I can see that it is configured with a number of lines like
obj-$(CONFIG_PCI) += pci/
Which directs make to build the pci module for instance. I think this implies that I should see a number .ko files. But I do not. I have seen just one .ko file for scsi module. I like to be able to build all of modules selected.
I also verified that a number of mudules are enabled when I issued:
make VARIANT_DEFCONFIG=msm8974_sec_hlte_spr_defconfig msm8974_sec_defconfig SELINUX_DEFCONFIG=selinux_defconfig gconfig
But as I said, I do not see any of them. What am I missing please?
#Subin - Thanks. I just tried make modules_install. I have to mention that I am cross compiling this for an arm target. I believe modules_install is for the purpose of installing the driver for the machine you are on? I got a message about needing to be in root, and I did not proceed. I have been wondering when I need to run it. What does it do exactly please?
Re: the make modules; I have run it before. I'll run it again and post the result. Since I got one .ko file I figured the issue is something different between that one module, and every other one enabled in my config. Here is what I got when I ran make modules:
sansari#ubuntu:~/WORKING_DIRECTORY$ make modules
CHK include/linux/version.h
CHK include/generated/utsrelease.h
make[1]: `include/generated/mach-types.h' is up to date.
CALL scripts/checksyscalls.sh
Building modules, stage 2.
MODPOST 1 modules
Re: your comment on the location of .ko files, I am doing a find to see if perhaps I am not looking at the right place, it only finds the one which was built. Not the other ones. Here is the output:
sansari#ubuntu:~/WORKING_DIRECTORY$ find . -type f -name "*.ko"
./drivers/scsi/scsi_wait_scan.ko
sansari#ubuntu:~/WORKING_DIRECTORY$
Should I perhaps run make v=1, in verbose mode that is? Would that provide more information on why the other modules are not built?
#Gil Hamilton - Thanks. You are right. Here is an excerpt of the .config file:
#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
CONFIG_CHR_DEV_SCH=y
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_SCSI_WAIT_SCAN=m
This entry is the only one set to 'm'.
Most device driver modules in the linux kernel build system use a tristate (3-valued) configuration setting. The options are
'n' (don't build at all),
'y' (build and link statically into the main kernel object), and
'm' (build as module for dynamic loading).
The values are determined by the content of .config. The values in .config are usually generated from an existing config file (look in arch/<ARCH>/configs for your <ARCH>). Also check the output of 'make help' for interesting configuration targets.
If you're not seeing the .ko files being created, that indicates the corresponding configuration variable is either set to 'y' or 'n'.

Packaging a library with Autotools

I'm starting out with Autotools, and I'm trying to package a library (a generic stack implementation for learning purposes) along with some usage examples.
The library source lives in src and the example in examples.
I have the following Makefile.am:
lib_LTLIBRARIES = libstack.la
libstack_la_SOURCES = src/stack.c
check_PROGRAMS = example/stack
example_stack_SOURCES = example/stack.c
example_stack_LDADD = libstack.la
As long as my understanding goes, I need to specify a header for libstack.la, and include that from my example, but I get the following error when running autoreconf after adding libstack_la_HEADERS = src/stack.h to Makefile.am:
$ autoreconf -iv
... (omiting irrelevant parts)
Makefile.am:3: error: 'libstack_la_HEADERS' is used but 'libstack_ladir' is undefined
autoreconf: automake failed with exit status: 1
I couldn't find any information related to the dir prefix.
What am I missing here?
To handle header of library you should write something like this:
libstackincludedir = $(includedir)/my_mega_stack
libstackinclude_HEADERS = stack.h

Resources