Why does building libgcc require crti.o and -lc? - c

To build a full libgcc with libc support, you need the libc headers, according to these guides (see also the --without-headers option in gcc configuration doc):
https://wiki.osdev.org/Hosted_GCC_Cross-Compiler
https://wiki.gentoo.org/wiki/Embedded_Handbook/General/Creating_a_cross-compiler#Cross-compiler_internals
So I tried it, and I get linker errors about crti.o not found and -lc not found. Then, I found this guide https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/, that installs only the crti.o files and a fake libc. So why does building libgcc need them? As I understand it, libraries don't need the C runtime files. Also, in step 5., when building libgcc, how does make know where to find the headers and runtime libraries, since --with-sysroot was never specified in the configure step. I know I can build a degraded libgcc at first, but I'd just like to understand why I need more than the headers to build a full libgcc.

Related

Must link to dependent libraries' dependents; why?

I have an application - let's call it "P" - that uses custom SO's: A.so, B.so, and C.so
The A.so library uses another custom library - D.so - as well as SSL and the math library.
The "P" application makes no calls whatsoever to SSL or math routines.
On macOS (with clang), I could build P with -lA -lB -lC and all was good.
I'm migrating everything to Linux (Debian) with GCC.
Now, when I bulid P, I have to -lA -lB -lC -lD -lm -lssl
What am I doing wrong?
I'm using simple makefiles - no autoconfig, no cmake, etc.
Could this be an "install_name_tool" vs. "chrpath" issue when I build the libraries?
This is because of a combination of the following two factors:
On macOS, the standard C library (libSystem.dylib) which is automatically linked by the compiler already includes a lot more functionality than on Linux. It may include some (or all) the necessary functions for your program. For example, as you can read from this documentation page, libSystem already includes the math library (which is a separate file on Linux and needs to be linked with -lm).
The shared libraries you are linking were compiled for macOS with additional functions already embedded into them, so those don't need to link to other shared libraries. It is not uncommon for a library to depend on different other libraries on different operating systems.
On the other hand, on Linux, the standard C library is split into different files: -lc is automatically linked by the compiler, but the math library (-lm) and other parts (-ldl, -lpthread, etc) are not, and therefore need to be linked manually.
Solved it. Turns out that clang - regardless of development platform - is a lot more forgiving with the order of parameters and options when linking. With clang, you can pretty much put your -I, -L, -l, other options and object files in whatever order you want. Not so with gcc; it's much more particular. clang made me lazy.

ld and lld use only paths I input

I am trying to cross compile for my raspberry pi, unfortunately the pi has an older version of libstdc++ than my build machine and when I try to run my executable it says "./<exe_name>: /usr/lib/arm-linux-gnueabihf/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by ./<exe_name>). I've gotten it working by using "-static", but really I'd like to be able to tell both ld (the gcc linker) and lld (the clang linker) "Only look in these paths for any libraries" it keeps finding the system one and linking against it. I've rsynced the raspberry pi's /usr/lib and /lib directores over to the host machine and I'd like to say "use /path_to_raspberry_pi_rsync/lib and /path_to_raspberry_pi_rsync/usr/lib" only.
Bonus points for getting ld and lld to tell me what path it's using when it tries to link.
I'd like to be able to tell both ld (the gcc linker) and lld (the clang linker) "Only look in these paths for any libraries"
Both will do that if you supply proper -L/path/to/target/libraries with sufficient contents.
it keeps finding the system one and linking against it. I've rsynced the raspberry pi's /usr/lib and /lib directores over to the host machine and I'd like to say "use /path_to_raspberry_pi_rsync/lib and /path_to_raspberry_pi_rsync/usr/lib" only.
Your problem most likely stems from the fact that what you rsynced are runtime libraries, not actual development libraries. So if e.g. /path_to_raspberry_pi_rsync/usr/lib contains libstdc++.so.6, but doesn't contain libstdc++.so symlink, then the linker will keep looking for libstdc++.so., until it finds one in the system directory.
In addition, once you succeed limiting your link to just the "rsync"d libraries, it is likely that your link will fail with unresolved libstdc++ symbols. That is because you need a matching set of headers and libraries.
Your best bet is to obtain a proper toolchain targeting your runtime environment.
Bonus points for getting ld and lld to tell me what path it's using when it tries to link.
With ld, you can add -Wl,-t flag and it will tell you about each and every library and object file it opens. lld may support this flag as well.

Go package linkage with a C library

I hope this is a basic question. I am trying to build a Go package which includes functions from a library written in C. The structure is basically as follows:
package too
/*
#cgo LDFLAGS: -L/usr/local/lib include -lbar
#include mybar.h
*/
import "C"
func MyGoWrapper () {
C.orig_func()
}
Running go build foo.go fails with an "undefined reference" for orig_func. Note that the header is mybar.h; I created a prototype for orig_func that was not included in the original library. Do I need to recompile the library first, including this header file, before it will link with the Go build? Or am I misunderstanding something else entirely?
When linking against an external library, you do need to separately compile it for your target architecture. cgo can't replace the configure/make (or whatever) to compile the library; it only knows how to build a few .c files in your package directory, and a library's build process might be more complex.
I'm less sure of how to accomplish the larger task of linking in an external library when cross-compiling (and I'm not sure what you've already done). The (closed) Go bug on cross-compilation with cgo looks useful here. You may want to build the Go toolchain with some environment variables set that are described in godoc cmd/cgo:
To enable cgo during cross compiling builds, set the CGO_ENABLED
environment variable to 1 when building the Go tools with make.bash.
Also, set CC_FOR_TARGET to the C cross compiler for the target. CC will
be used for compiling for the host.
After the Go tools are built, when running the go command, CC_FOR_TARGET
is ignored. The value of CC_FOR_TARGET when running make.bash is the
default compiler. However, you can set the environment variable CC, not
CC_FOR_TARGET, to control the compiler when running the go tool.
CXX_FOR_TARGET works in a similar way for C++ code.
The bug also mentions someone who uses -ldflags="-extld=$(CC)" (where $(CC) is the name of the cross-compiler they want to use).
In your example code there's an explicit -L/usr/local/lib and I don't think that'll work: I think when you build libraries for the target, you're going to want to put them in a directory distinct from the lib for your host arch. For example, this ARM cross-compilation HOWTO uses a /usr/local/arm-linux prefix or install_root in some places.

How to created a shared library (dylib) using automake that JNI/JNA can use?

How do I convince LibTools to generate a library identical to what gcc does automatically?
This works if I do things explicitly:
gcc -o libclique.dylib -shared disc.c phylip.c Slist.c clique.c
cp libclique.dylib [JavaTestDir]/libclique.dylib
But if I do:
Makefile libclique.la (which is what automake generates)
cp .libs/libclique.1.dylib [JavaTestDir]/libclique.dylib
Java finds the library but can't find the entry point.
I read the "How to create a shared library (.so) in an automake script?" thread and it helped a lot. I got the dylib created with a -shared flag (according to the generated Makefile). But when I try to use it from Java Native Access I get a "symbol not found" error.
Looking at the libclique.la that is generated by Makefile it doesn't seem to have any critical information in it, just looks to be link overloads and moving things around for the convenience of subsequent C/C++ compiler steps (which I don't have), so I would expect libclique.1.dylib to be a functioning dynamic library.
I'm guessing that is where I'm going wrong, but, given that JNA links directly to a dylib and is not compiled with it (per the example in the discussion cited above), it seems all the subsequent compilation steps described in the LibTools manual are moot.
Note: I'm testing on a Mac, but I'm going to have to do this on Windows and Linux machines also, which is why I'm trying to put this into Automake.
Note2: I'm using Eclipse for my Java development and, yes, I did import the dylib.
Thanks
You should be building a plugin and in particular pass
libclique_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
This way you tell libtool you want a dynamically loadable module rather than a shared library (which for ELF are the same thing, but for Mach-O are not.)

Do I really need to specify library location for linking with automake?

I am working on a multi-platform C program. The makefile has become pretty complicated because of all the different compilers, library locations, etc. on each machine. I figured Autoconf/Automake would be a good solution, though my previous experience using those tools was minimal.
My Makefile.am has the line LIBS=-lX11, but linking fails with the error "/usr/bin/ld: cannot find -lX11". I can work around this by adding "-L/usr/X11R6/lib/" to the definition of LIBS, but should I really need to do that? When I run ./configure, it says:
checking for X... libraries /usr/X11R6/lib, headers /usr/X11R6/include
So it seems like Automake should know where to find it. Is there a way I can reference its location in Makefile.am without having to hardcode it, since the X11 libs will be in a different place on each machine?
Your Makefile.am should not set LIBS. If you need to link with a library, configure.ac should include a check for the library and the configure script will set LIBS accordingly. Also, Makefile.am should not specify paths to libraries. Each system should be configured so that the precompiler can find the headers and the linker can find the libraries. If the system is not set up so that the linker can find a library, the correct solution is for the user to specify the location in LDFLAGS rather than hard coding something in Makefile.am. (eg, rather than adding -L/p/a/t/h to a Makefile, you should add LDFLAGS=-L/p/a/t/h to the invocation of configure.)

Resources