Packaging a library with Autotools - makefile

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

Related

Yocto Transaction Test, two recipes install the same file

I am adding a custom recipe to my image. It is bases on DBCPPP. This project is built using cmake. My issue only comes to light when I include a new layer meta-swupdate. It seems meta-swupdate alters the kernel in a way that conflicts with dbcppp. My full error is:
Error: Transaction test error:
file /usr/lib/libxml2.so.2.9.10 conflicts between attempted installs of dbcppp-1.0+gitr0+fa8ce17468-r0.cortexa7t2hf_neon and libxml2-2.9.10-r0.cortexa7t2hf_neon
To build and include dbcppp I added the recipe:
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "gitsm://github.com/xR3b0rn/dbcppp.git;protocol=https;branch=master"
PV = "1.0+gitr${SRCPV}"
SRCREV = "${AUTOREV}"
DEPENDS += " boost"
S = "${WORKDIR}/git"
inherit pkgconfig cmake
FILES_${PN} += "/usr/lib/xml2Conf.sh /usr/lib/lib*.so.*"
SOLIBS = ".so"
FILES_SOLIBSDEV = ""
INSANE_SKIP_${PN} += "dev-so"
I have read a few other questions and attempted two solutions by adding a do_install_append step.
Change folder permission level install -d 0755 ${D}/usr/lib
Remove the folder rm -rf ${D}/usr/lib
Neither solution worked. I need both libraries in my application and I unsure how to proceed.
Edit: After some further reading I found a suggestion to delete the tmp, cache, and sstate-chace folders. I did this but I receive the same error.
Edit: My local.conf has PACKAGE_CLASSES ?= 'package_rpm' defined. if I remove this I still get a do_rootfs error, but the error message is not helpful.
Edit: In my recipe for dbcppp I have attempted to remove the file in question. This gives me the same error. Makes no difference.
do_install_append() {
rm -rf /usr/lib/libxml2.so.2.9.10
}

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/

ruby native extension: undefined symbol

I'm attempting to create a ruby native extension, but when I run rake which uses ext/example_project/extconf.rb to build my project and run my tests under test/, I get the following error when the tests are run:
./home/jbuesking/.rbenv/versions/2.3.0/bin/ruby: symbol lookup error:
/home/jbuesking/repositories/example_project/lib/example_project/example_project.so: undefined symbol: some_function
I'm pretty sure my files are not being linked correctly and that I need to alter my extconf.rb and/or Rakefile in some way, but I'm not sure how.
I've created a simple repository that demonstrates the issue over on GitHub. It'll fail with the same error if you clone it and run rake from the projects root.
Some additional information:
I used the ruby gem hoe to create the project via sow example_project
The failing function is attempting to call a function defined in the subdirectory ext/example_project/c_example_project. My actual project uses a git submodule from the ext/example_project directory, which in turn sets up the submodule as a subdirectory. The submodule is a c project with a flattened structure (all files in the root directory). Note: That wording may be confusing, but the key point is that there's a nested c project defined at ext/example_project/c_example_project which has methods I'm trying to call.
Let me know if any clarification is needed, and I'll do my best to provide it.
So, there are some interesting issues you have here. By default, mkmf doesn't actually support specifying multiple directories for building sources.
There is a workaround, as seen here (Takehiro Kubo's comment about setting objs):
https://www.ruby-forum.com/topic/4224640
Basically, you construct the $objs global in your extconf.rb file yourself.
Using your github code, here's what I added to the extconf.rb and got to work
extconf.rb
globs = [".", "c_example_project"].map do |directory|
File.join(File.dirname(__FILE__), directory)
end.join(",")
$objs = Dir.glob("{#{globs}}/*.c").map do |file|
File.join(File.dirname(file), "#{File.basename(file, ".c")}.o")
end
Notice I'm actually constructing an absolute path to each of the c sources, for some reason rake-compiler was freaking out if we were just globbing with {.,c_example_project}/*.c, presumably since it's running the extconf.rb file from another directory.
In addition, your tests/c extensions have a few errors in them. Making the following change in example_project.c fixes the test failure:
static VALUE example_project_c_code_function()
{
- return some_function();
+ VALUE _string = rb_str_new2(some_function());
+ int _enc = rb_enc_find_index("UTF-8");
+ rb_enc_associate_index(_string, _enc);
+ return _string;
}
Explanation
Basically even though you're checking the c_example_project.h header in your extconf.rb, you're not actually generating the object file where some_function is defined. So, when linking the final dynamic library that ruby loads up, there's no definition for some_function and you get your error.
I don't have any experience with building native extensions, but from mkmf source code it looks like you can only specify one source directory. I moved both files from c_example_project to the parent directory and everything was linked properly. I think that is how you should do it. All common gems (like pg, nokogiri etc) have such code structure, all *.c and *.h files are in one directory.
You can always create Makefile yourself, but that would require too much work to maintain.
PS. Your project compiled successfully, but you there is segmentation fault, because you should return proper ruby string object in some_function and not pointer to a string.
photoionized has a great answer, but $obj can be an array instead of an Enumerator.It seems to be okay to simply use an absolute path.
$objs = Dir.glob([".c", "libfoobar/*.c"], base: __dir__)
.map { |f| File.expand_path(f, __dir__) }
.map { |f| f.sub(/\.c$/, ".o") }

libtool: what is the path to my module?

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.

Resources