Combine static libraries on Apple - objective-c

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

MSYS2+MinGW64: why do ldd and objdump find different DLL dependencies?

I get different DLLs dependencies reported by different tools and like to deeply understand why. So answers like "tool xxx is crap, use cool yyy" are opinions and not welcome. Answers like "you have wrong path order" or "you missed to export XXX=yyyy" are not what I focus for, but if they are applicable, those are welcome too. What I exactly want to understand is for instance, which PE/ELF tables which of the tools use and which they can't see. All under the aspect of mingw / msys2 environment.
For completeness: I compiled my program inside Codelite IDE following exactly this Setup Instructions for Codelite and inserted /mingw64/bin:/clang64/bin: in front of PATH. The expectation is that this has nothing to do with my observation. Just for the case I couldn't see the wood because of all the trees. Inserted my code into the helloworld example.
For completeness II: the ucrt variant is installed for different projects. I did not use it here.
For completeness III: I give all my instructions here. Expecting, 80% have nothing to do with the question, but just in case you see things I missed.
Given: MSYS2 (Sept.2022, msys2-x86_64-20220904.exe) with:
pacman -Suy \
mingw-w64-x86_64-gcc \
base-devel development \
sys-utils \
mingw-w64-ucrt-x86_64-toolchain mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain \
libmodbus \
mingw-w64-x86_64-codelite
Opened a MSYS terminal:
$ which gcc && which g++ && which clang
/mingw64/bin/gcc
/mingw64/bin/g++
/mingw64/bin/clang
codelite &
Inside Codelite I only changed Settings | Build Settings | Compilers to "MinGW 32bit (MSYS2 64bit)" and therein the two cfg lines:
make C:/c/msys64/mingw32/bin/mingw32-make.exe -j8 SHELL=sh.exe
makedir mkdir -p
Program was then built via codelite generated makefile:
C:\WINDOWS\system32\cmd.exe /C C:/c/msys64/mingw32/bin/mingw32-make.exe -j8 SHELL=sh.exe -e -f Makefile
...[cut]...
C:/c/msys64/mingw32/bin/g++.exe -c protocol_writer.cpp" -g -O0 -Wall -o Debug/protocol_writer.cpp.o -I. -I.
C:/c/msys64/mingw32/bin/g++.exe -c scan_dtsu666_main.cpp" -g -O0 -Wall -o Debug/scan_dtsu666_main.cpp.o -I. -I.
C:/c/msys64/mingw32/bin/g++.exe -o Debug/modbus-dtu-dump #"modbus-dtu-dump.txt" -L. -lmodbus
====0 errors, 0 warnings====
Program was not starting because of missing DLLs (no pop-up or error msg). Now we come to the core issue. I invoked:
$ which ldd
/usr/bin/ldd
$ ldd modbus-dtu-dump.exe
ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffdf2c70000)
ntdll.dll => /c/Windows/SysWOW64/ntdll.dll (0x77310000)
wow64.dll => /c/WINDOWS/System32/wow64.dll (0x7ffdf2510000)
wow64win.dll => /c/WINDOWS/System32/wow64win.dll (0x7ffdf1be0000)
$ which objdump
/mingw64/bin/objdump
$ objdump --private-headers modbus-dtu-dump.exe | grep 'DLL'
DLL Name: libgcc_s_dw2-1.dll
DLL Name: KERNEL32.dll
DLL Name: libmodbus-5.dll
DLL Name: msvcrt.dll
DLL Name: libwinpthread-1.dll
DLL Name: libstdc++-6.dll
... and wonder, why ldd doesn't tell anything about the mingw runtimes, while objdump doesn't tell about the windows os core dependencies.
Edit:
As I wrote in a side note "Program was not starting because of missing DLLs (no pop-up or error msg).", there seems to be another miss-configuration. Once I changed the IDE settings to use the 64bit target, it was able to start and all-aspect debugging. I'll keep this up to date, for the case Google leads some people to here, searching for similar codelite or mingw problems. Goal is to have both architectures compile-able and debug-able.

Cannot install regular files for Yocto using CMake

I have been using autotools for a few years, and I'm learning CMake now for new projects.
Here is what I have:
myfirstrecipe.bb:
inherit pkgconfig cmake
...
do_install() {
install -d ${D}${datadir}/folder1/folder2
install -m 0755 ${S}/files/file.txt ${D}${datadir}/folder1/folder2
}
mysecondrecipe.bb:
...
DEPENDS = "myfirstrecipe"
...
This works fine. The second recipe can find the file.txt installed by the first recipe, which I see it is installed in the secondrecipe sysroot:
build/tmp/work/armv7ahf-vfp-os-linux-musleabi/mysecondrecipe/510-r0/mysecondrecipe-sysroot/usr/share/folder1/folder2/file.txt
However I want CMake to install the file instead. So when I try this:
myfirstrecipe.bb:
inherit pkgconfig cmake
...
OECMAKE_TARGET_INSTALL = "file-install"
CMakeLists.txt:
add_custom_target(file-install)
add_custom_command(TARGET file-install POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_DATADIR}/folder1/folder2
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_SOURCE_DIR}/files/file.txt
${CMAKE_INSTALL_DATADIR}/folder1/folder2/)
Then I get a build error from mysecondrecipe.bb saying it could not find the file since it is not installed. I see it installed here:
build/tmp/work/armv7ahf-vfp-os-linux-musleabi/myfirstrecipe/1.0-r0/myfirstrecipe-1.0/share/folder1/folder2/file.txt
But not in the path above. Anyone can see what I am missing? If I were to use Autotools I could easily get this working with this:
Automake.am:
file-install: $(shell find files/ -type f -name '*.txt')
mkdir -p ${DESTDIR}${datadir}/folder1/folder2
cp -u $^ -t ${DESTDIR}${datadir}/folder1/folder2
Basically you do not use the standard way of installing files.
CMake has an install directive install, wich is commonly used and powerfull.
Doing so, leads to the nice situation, that Within myfirstrecipe.bb an own do_install task is not necessary. The cmake.bbclass, you already inherit, is adding a do_install task and relies on the install directive within your CMakeLists.txt
You can take a look at the cmake.bbclass to see how it is implemented. It's at poky/meta/classes/cmake.bbclass
I guess that switching to install will make life easier

Objective-C for Windows with Gitbash and GCC

When I compile things with gitbash and gcc, is there someway to shorten what I need to type?
In order to compile my helloworld program, I have to type the following in:
gcc -o helloworld.exe helloworld.m -I C:/GNUstep/GNUstep/System/Library/Headers -L C:/GNUstep/GNUstep/System/Library/Libraries -std=c99 -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
Most people use Makefiles (or something related, e.g. CMake) in order to ease development. Makefiles are similar to bash scripts (the syntax is similar as well). After you created a Makefile you can run make and it does exactly what you specified.
If you want to know how to run Automake on Windows, read this: How to run a makefile in Windows?

MinGW linking dynamic library with bad name

I am using MinGW64 (Windows 7) without MSYS and I have the following problem:
I have one dll, written in C99, which has to have the .mexw64 suffix so it can be used by Matlab. I would like to be able to link this dll form another dll (mexw64) dynamically but gcc won't allow me to link directly. I cannot do static linking, because both dlls have many functions of the same name which can be hidden by not exporting their symbols when creating the shared library.
So far, I have tried:
To create a symbolic link (with correct suffix and preffix) using mklink. This works, but I was not able to run mklink from the makefile. Maybe it is due to the fact I am not using MSYS which could have ln -s (I havent checked).
To do the copy of the first dll and correcting the suffix and prefix. This worked better than I expected, because on runtime the second dll actually uses the original .mexw64 and not the dll copy. I guess it is just because the .mexw64 is found first, but why is that .mexw64 searched in the first place? How the system know it is actually a dll?
My question is, is this correct/safe enough? Are there any other options?
Thanks for comments.
You should build a proper implib, either as a linker output or from a .def.
Linker:
$ gcc -shared -o testimpl.mexw64 testimpl.c -Wl,--out-implib,libtestimpl.a
$ dlltool -I libtestimpl.a
testimpl.mexw64
Or create a .def file, specifying an explicit LIBRARY:
$ cat testimpl.def
LIBRARY testimpl.mexw64
EXPORTS
test #1
$ dlltool -d testimpl.def -l libtestimpl.a
$ dlltool -I libtestimpl.a
testimpl.mexw64
And finally, link stuff:
$ gcc -o test.exe test.c libtestimpl.a
# or
$ gcc -o test.exe test.c -L. -ltestimpl
$ grep testimpl.mexw64 test.exe
Binary file test.exe matches

Unbound modules in OCaml

My problem is that ocamlc and ocamlopt apear to be refusing to find third party libraries installed through apt-get. I first started having this problem when I tried to incorporate third-party modules into my own OCaml programs, and quickly wrote it off as a personal failing in understanding OCaml compilation. Soon-- however-- I found myself running into the same problem when trying to compile other peoples projects under their own instructions.
Here is the most straight-forward example. The others all use ocamlbuild, which obfuscates things a little bit.
The program: http://groups.google.com/group/fa.caml/msg/5aee553df34548e2
The compilation:
$ocamlc -g -dtypes -pp camlp4oof -I +camlp4 dynlink.cma camlp4lib.cma -cc g++ llvm.cma llvm_bitwriter.cma minml.ml -o minml
File "minml.ml", line 43, characters 0-9:
Error:Unbound module Llvm
Even when I provide ocamlc with the obsolute paths to the llvm files, like so...
$ ocamlc -g -dtypes -pp camlp4oof -I +camlp4 dynlink.cma camlp4lib.cma -cc g++ /usr/lib/ocaml/llvm-2.7/llvm.cma /usr/lib/ocaml/llvm-2.7/llvm_bitwriter.cma minml.ml -o minml
... to no avail.
What am I doing wrong?
Your command is doing two things: it's compiling minml.ml (into minml.cmo), then linking the resulting object into minml.
Compiling a module requires the interfaces of the dependencies. The interfaces contain typing information that is necessary to both the type checker and the code generator; this information is not repeated in the implementation (.cma here). So for the compilation stage, llvm.cmi must be available. The compiler looks for it in the include path, so you need an additional -I +llvm-2.7 (which is short for -I /usr/lib/ocaml/llvm-2.7).
The linking stage requires llvm.cma, which contains the bytecode implementation of the module. Here, you can either use -I or give a full path to let ocamlc know where to find the file.
ocamlc -g -dtypes -I +camlp4 -I +llvm-2.7 -pp camlp4oof -c minml.ml
ocamlc -g -cc g++ -I +camlp4 -I +llvm-2.7 dynlink.cma camlp4lib.cma llvm.cma llvm_bitwriter.cma minml.cmo -o minml
or if you want to do both stages in a single command:
ocamlc -g -dtypes -cc g++ -I +camlp4 -I +llvm-2.7 dynlink.cma camlp4lib.cma llvm.cma llvm_bitwriter.cma -pp camlp4oof minml.ml -o minml