How to merge libraries in linux [duplicate] - static-libraries

I tried the approach in this question, but it seems the linux version of ar is not the same as the mac version since I failed to combine the object files again.
What I basically want to do is is merge another static library into my Xcode static library build product via a run-script build phase.
Unfortunately I can't compile the other library directly into my project because it has it's own build system (therefore I use the compiled libs).
I think it should be possible to merge the other library via ar into the Xcode generated library without decompiling the build product. How do I accomplish this?

you can use libtool to do it
libtool -static -o new.a old1.a old2.a

If you're dealing with multi-architecture static libraries, a bit of extra manipulation is required to thin each library, combine the thinned versions, and then fatten the result. Here's a handy script which you can edit to your satisfaction which does all that in one. The example takes three iOS libraries path/to/source/libs/libone.a, path/to/source/libs/libtwo.a, and path/to/source/libs/libthree.a and merges them into a single library libcombined.a.
#! /bin/bash
INPATH="path/to/source/libs"
LIBPREFIX="lib"
LIBS="one two three"
LIBEXT=".a"
OUT="combined"
ARCHS="armv7 armv7s arm64"
for arch in $ARCHS
do
for lib in $LIBS
do
lipo -extract $arch $INPATH/$LIBPREFIX$lib$LIBEXT -o $LIBPREFIX$lib-$arch$LIBEXT
done
INLIBS=`eval echo $LIBPREFIX\{${LIBS// /,}\}-$arch$LIBEXT`
libtool -static -o $LIBPREFIX$OUT-$arch$LIBEXT $INLIBS
rm $INLIBS
done
OUTLIBS=`eval echo $LIBPREFIX$OUT-\{${ARCHS// /,}\}$LIBEXT`
lipo -create $OUTLIBS -o $LIBPREFIX$OUT$LIBEXT
rm $OUTLIBS

You should just be able to link one to the other. So... just use ld to merge the images.

You should use ar -r to create an archive on MacOS:
ar -x libabc.a
ar -x libxyz.a
ar -r libaz.a *.o

Related

ld: building for macOS-x86_64 but attempting to link with file built for macOS-x86_64

I have this strange issue where creating / using a static library works in my Ubuntu VM but not on macOS:
ld: warning: ignoring file ./dist/libXXXX.a, building for macOS-x86_64 but attempting to link with file built for macOS-x86_64
Command to create the static library is:
ar rcs libtest.a obj1.o obj2.o ...
Compiler invocation:
gcc -g -Wall -Wextra main.c -L./dist -lXXXX -o main
Searching on google didn't yield any usable results except for this (maybe) related question on SO:
Possible related question
I realize this is an old post and you found your fix, but let me post this here for anyone else who runs into this problem for whom these answers don't provide a solution.
You might be using two different toolchains unknowingly, one from Apple (installed via Xcode) and one from GNU (installed via Home-brew or MacPorts). If you type ranlib --version and see version info showing that ranlib is GNU, this is likely the case.
Make sure that /usr/bin comes in your $PATH before /usr/local/bin and /opt/local/bin. When you run which -a ranlib, the first result in the list should be /usr/bin/ranlib. Same for which -a ar-- the first result should be /usr/bin/ar. If it is not so, you need to fix your $PATH.
Once you fix your path and clean your project, try building again and things should work.
The issue was solved when I directly put those object files rather than gathering them into a static library, i.e.,
gcc -g -Wall -Wextra main.c obj1.o obj2.o -o main
After that, I got many warnings like ld: warning: object file (obj1.o) was built for newer macOS version (11.0) than being linked (10.14), but it is a warning, and the object is linked, so the problem is solved.
The root cause is that some library passes -mmacosx-version-min=10.14 to gcc, so the object file is built for 10.14, but my macos is now 11.0.
If you want to make things work, try directly using object files rather than creating a static library.
If you want to resolve all the warnings, find ``-mmacosx-version-min` and comment it.
After looking at my script that automatically creates the static library I've found the culprit:
For some reason my tool created object files for header files (resulting in files like header.h.o).
Removing those fixed the issue.

How to build openssl for M1 and for Intel?

I have a project which needs to use Libcrypto - and I have two versions of Libcrypto (libcrypto.a (from OpenSSL 1.1.1) built for ARM64) and (lcrypto.a (from OpenSSL 1.0.2) for Intel). Leaving aside the issues of whether it's good practice or not to have two different versions, I can say that if I include libcrypto.a then I can build and run on M1 and it works fine on M1. If I include lcrypto.a then I can build and run on Intel and it works fine on Intel. What I can't do is include them both (linker error - The linked library 'lcrypto.a' is missing one or more architectures required by this target: arm64.) - and if I can't include them both then I can't build a fat binary, and my app is less than entirely useful!
My question is How can I include both in my project - or where can I get (and how can I include) a fat version of Libcrypto? I've looked at this https://github.com/balthisar/openssl-xcframeworks/releases and this https://developer.apple.com/forums/thread/670631 but I'm none the wiser. I think I built a Fat Binary - but the Fat Binary I thought that I built doesn't work for either architecture!
Use command lipo to combine binaries
Compile Intel and ARM versions separately (arm version requires Xcode 12).
export MACOSX_DEPLOYMENT_TARGET=10.9
cp -r openssl-1.1.1t openssl-1.1.1t-arm64
cp -r openssl-1.1.1t openssl-1.1.1t-x86_x64
Build the Intel half
cd openssl-1.1.1t-x86_x64
./Configure darwin64-x86_64-cc shared
make
NOTE: For openssl-1.1.1q use -Wno-error=implicit-function-declaration as a configure parameter
Build the Arm half
export MACOSX_DEPLOYMENT_TARGET=10.15 /* arm64 only with Big Sur -> minimum might be 10.16 or 11.0 */)
cd ../openssl-1.1.1t-arm64
./Configure enable-rc5 zlib darwin64-arm64-cc no-asm
make
NOTE: For openssl-1.1.1q use -Wno-error=implicit-function-declaration as a configure parameter
To create universal binary use command lipo:
cd ..
mkdir openssl-mac
lipo -create openssl-1.1.1t-arm64/libcrypto.a openssl-1.1.1t-x86_x64/libcrypto.a -output openssl-mac/libcrypto.a
lipo -create openssl-1.1.1t-arm64/libssl.a openssl-1.1.1t-x86_x64/libssl.a -output openssl-mac/libssl.a
Verify that resulting binary contains both architectures:
file libcrypto.a libssl.a
libcrypto.a: Mach-O universal binary with 2 architectures: [x86_64:current ar archive random library] [arm64]
libcrypto.a (for architecture x86_64): current ar archive random library
libcrypto.a (for architecture arm64): current ar archive random library
libssl.a: Mach-O universal binary with 2 architectures: [x86_64:current ar archive random library] [arm64]
libssl.a (for architecture x86_64): current ar archive random library
libssl.a (for architecture arm64): current ar archive random library
PS: If you plan to use dynamic library combine dylib files using lipo and run instal_name_tool
cd openssl-mac
install_name_tool -id '#rpath/libcrypto.1.1.1.dylib' libcrypto.1.1.1.dylib
install_name_tool -id '#rpath/libssl.1.1.dylib' libssl.1.1.dylib
otool -D libssl.1.1.dylib /* to verify */
Result:
libssl.1.1.dylib:
#rpath/libssl.1.1.dylib
Even though this question already has an accepted answer, I'd like to mention that I found an easier way to do this that doesn't require using lipo, just in case it helps make someone else's life easier.
The trick is to force it to compile for both architectures simultaneously.
Before calling Configure in the openssl source directory, create a file somewhere convenient (for the purposes of explaining I'll just have it in the home folder) named cc, and have it contain the following text:
#!/bin/bash
if [[ $* == *-arch\ x86_64* ]] && ! [[ $* == *-arch\ arm64* ]]; then
echo Forcing compilation with arm64
cc -arch arm64 $#
else
cc $#
fi
That script will automatically add -arch arm64 to any compilation command that only includes -arch x86_64, and leave all other compilation commands unmodified.
Give it execute permissions:
chmod a+x ~/cc
Then execute the following in your shell to force compilation with this shell script:
export CC=/Users/yourname/cc
Then proceed with configuring and building as though for arm64, but tell it to compile as x86_64:
./Configure enable-rc5 zlib no-asm darwin64-x86_64-cc
make
make install
The resulting static libs and dylibs will already be x86_64 / arm64 universal!

Linking against static Lua libraries on macOS

I'm trying to compile and link a program (using CMake) that uses Lua 5.3's C interface on Mac OS X 10.15.7. However I have these problems:
brew install lua#5.3 only installs dynamic libraries
I cannot copy static libraries built from source to /usr/local due to System Integrity Protection (?)
I don't know how to make CMake find the libraries if I put them anywhere else (using find_package(Lua 5.3 REQUIRED)
What's the easiest way to solve this?
If I correctly understand your question, you are trying to use Lua's C API, which means that you need access to the principal header files lua.h, lualib.h, and lauxlib.h, as well the static library liblua.a that is created when the interpreter is built.
I would recommend downloading lua-5.3.5.tar.gz from lua.org and then building from source.
This can be done easily from the Terminal:
$ wget http://www.lua.org/ftp/lua-5.3.5.tar.gz
$ tar xzf lua-5.3.5.tar.gz
$ cd lua-5.3.5
$ make macosx
After that you should be able to do make install as well, which copies the Lua interpreter to /usr/local/bin, I believe.
If you do not want the key Lua header files put into your include path, build your program with -I and -L flags. Also, don't forget the -llua -ldl -lm flags when linking your program.

Cross compiling PCRE with CodeSourcery toolchain?

I am trying to compile PCRE with CodeSourcery
here is my configure script
#!/bin/bash
PROJECT_BASE=$(pwd);
PROJECT_REPOSITORY=$PROJECT_BASE/download
INSTALL_PREFIX=$PROJECT_BASE/compiled/armv5te
mkdir -p $INSTALL_PREFIX && mkdir -p $PROJECT_BASE/download && mkdir -p $PROJECT_BASE/build
export TOOL_PREFIX=${HOME}/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux
SYSROOT=$HOME/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/arm-none-linux-gnueabi/libc
export CC="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-gcc --sysroot=$SYSROOT"
export CXX="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-g++ --sysroot=$SYSROOT"
#CC="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-gcc"
#CXX="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-g++"
export AR="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-ar"
export RANLIB="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-ranlib"
export LD="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-ld"
export STRIP="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-strip"
export NM="${TOOL_PREFIX}/bin/arm-none-linux-gnueabi-nm"
export CCLD=$LD
export CHOST=arm-none-linux-gnueabi
PARENT_DIR=$(pwd);
cd $PROJECT_BASE/build && tar -xzvf $PROJECT_REPOSITORY/pcre-8.34.tar.gz && cd ./pcre-8.34
#LDFLAGS_DEP="-lc"
#CPPFLAGS="-I${INSTALL_PREFIX}/include"
# CFLAGS="-march=armv5t -marm -mlittle-endian -mglibc -static -I${INSTALL_PREFIX}/include"
LDFLAGS="-L${INSTALL_PREFIX}/lib"
./configure --prefix=$INSTALL_PREFIX/pcre --with-sysroot --target=arm-none-linux-gnueabi --host=x86_64 && make && make install;
cd -;
cd ${PARENT_DIR};
now it is successfully compiled but when i tried to execute that binary on android i get:
./pcregrep: not found
also having similar issue when cross-comping curl, openssl but when i run a test code
#include <stdio.h>
int main(){
printf("Hell ya it works");
return 0;
}
and compile with following option
arm-none-linux-gnueabi-gcc hello.c -static -o hello.c
it works
You're trying to use a Linux compiler with Android. It's not completely broken because Android is Linux, but Android doesn't come with the same set of libraries, as standard.
It's probably possible to install the Linux libraries (from the appropriate CodeSourcery libc directory), but that's a tricky process because the Android files will already be in the standard locations so they'll have to be installed to one side, somehow, and if you don't know what you're doing it'll get into a horrible mess.
The best solution is probably to use entirely static linking. That said, you might still find that libcurl is unhappy because, even statically linked, it requires that it can dlopen the DNS library of the host system, and I don't know how Android likes to do that.
I would suggest you try to get hold of a purpose-built Android toolchain (I believe Linaro do one) that is designed to use Android's "Bionic" C library, rather than GNU/Linux's "Glibc".
Its a mismatch between libc of code-sourcery tool-chain and libc which is in target rootfs.
libc in the host cross-compiler and deployed on the device rootfs are different
arm-none-linux-gnueabi-gcc hello.c -static -o hello.c
it works `
This works since you compiling statically so there is no need to copy libc to target here.
But pcre you built dynamically .check file ./pcregrep if its dynamic linked then
one easiest way compile statically as hello eg. and run on your target.
otherwise copy libc from tool chain to target and export it then it will work

libtool vs ar for creating a static library (xcode linker)

Creating a static library on Mac 10.5 with xcode via libtool and with ar via the command line both generate a libMainProject.a file however, when trying to use the one generate by libtool to link into a xcode application I end up with multiple message like
"vtable for project1 referenced from:
_ZTV27project1$non _lazy _ ptr in libMainProject.a(project1.o)"
Using the ar one is totally fine and links correctly. I have tried the addition of the -c option to the libtool while linking but that does not seem to have an impact. So I guess my 2 options are
1) Figure out what is causing the differences in symbols between the ar and libtool version and make the libtool generate the same information.
2) Make xcode use ar instead of libtool to generate the static libs.
Any ideas or suggestions would be appreciated.
Thanks in advance.
I suggest to unarchive the static library with ar. You will end up with the *.o files. Then use gobjdump (you might have to install that yourself from MacPorts/fink/homebrew) to see what's inside the *.o files and compare the two versions.

Resources