Link only what is used/needed with Clang on MacOS - macos

On MacOS, the dynamical linking behaviour seems to be fundamentally differnt from that of *Nix.
The problem is that on MacOS, Clang adds whatever libraries given at linking time to the produced binary, regardless of whether their symbols are needed or not.
Minimal C-example:
main.c
#include <stdio.h>
int main(void)
{
puts("Hello World!");
return 0;
}
foo.c
int foo(void)
{
return 42;
}
Compiling on MacOS with
clang -dynamiclib -o libfoo.dylib foo.c
clang -o main main.c -L. -lfoo
and then, using otool -L main, one finds that main binary depends on libfoo.dylib, althought it does not need the symbols in libfoo.dylib at all.
Under Linux, the result is different: Using
gcc -shared -fPIC -o libfoo.so foo.c
gcc -o main -L. -lfoo
to compile and then, ldd main shows no dependence on libfoo.so.
Tested with Apple Clang 12.0.0 and gcc 10.2.1 (Debian 10.2.1-6).
How could one reproduce the behaviour on Linux (“Link what you use/need”), when compiling and linking on MacOS?

Related

Error when cross compiling shared so which depends on another so

I am trying to cross compile my application for a arm based system.
I have 2 libraries compiled in the following way:
$ gcc -shared --sysroot=$DIR_PATH -o $LIBPATH/libfoo.so foo.o
$ gcc -shared --sysroot=$DIR_PATH -o $LIBPATH/libbar.so bar.o
A third library is compiled:
gcc -shared -o $LIBPATH/libfoobar.so --sysroot=$DIR_PATH -L$LIBPATH -Wl,rpath=$RUN_TIME_PATH foobar.o -lfoo -lbar
Then finally I compile a binary:
gcc -o app --sysroot=$DIR_PATH -L$LIBPATH -Wl,rpath=$RUN_TIME_PATH app.o -lfoobar
However when compiling app I get
warning: libfoo.so, needed by libfoobar.so, not found (try using -rpath or -rpath-link)
I believe you need to use -Wl,-rpath-link=$LIBPATH to tell the linker where to look to resolve runtime library references during the link operation.
More info can be found in the ld documentation: https://sourceware.org/binutils/docs-2.37/ld/Options.html

Can compile and link use different compilers when cross-compile?

I'd like to know if I can use different compilers for compile and link.
For example ,I have two files ,a.c and b.c,
I use clang to compile a.c and b.c:
clang -c a.c -o a.o
clang -c b.c -o b.o
and then use gcc to link the two .o file as a so library:
gcc -lm -lz -shared a.o b.o -o libad.so
I generate the so file successfully,but the app will crash when using this library.
Update:
More detailed information: What I have done is cross-compile , and target platform is armv7a.I use android-NDK and compile the codes on MAC.So the gcc is arm-linux-androideabi-gcc and clang is arm-linux-androideabi-clang.
Unless special flags are specified at link time (-fuse-ld=xxx[1][2]), both clang and gcc call the default system linker (which on macOS is lld and will probably be gold on linux). So running the second statement with either gcc or clang will produce the same linked binary.
[1] https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
[2] http://clang-developers.42468.n3.nabble.com/LLD-to-be-the-default-linker-in-Clang-td4053949.html

I'm having an issue linking the standard crt when using clang in linux with c++

I'm working on porting a windows project to linux so I am trying to learn/setup my build pipeline on linux(ubuntu). I use clang on windows and would like to use clang/llvm to compile my code on ubuntu but I am having an issue linking the c runtime library to my code. Here's an example of what I am trying to run just so I can set up the build scripts,
// -- system includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// -- my includes
#include "crt.h"
int main() {
char title[] = "Text";
int title_length = strlen(title);
// -- sending string and length to platform dependent code
CreateBox(title, title_length);
return(0); }
After installing clang 3.4 on Ubuntu 14.04 LTS I run the above code as well as platform dependent code from the terminal,
clang++ -c main.cpp box_linux.cpp
The file compiles without error. Let's say I had I use the following command when trying to link,
ld main.o box.o
I get back the following error every single time,
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
In function 'main':
(.text+0x30): undefined reference to 'strlen'
I try linking libc++, libstdc++ but nothing seems to work. I am admittedly very, very new to linux and clang on linux so I apologize in advance. I have checked different questions here on stackoveflow as well as ubuntu's forums and LLVM's forums/docs to no avail. If anyone could point me in the right direction it would be greatly appreciated.
If you are using clang (or gcc) on linux you don't have to do the linking on your own. You can let clang do the linking for you and it will select the necessary libraries for your system just remove the -c flag form command line or use clang main.o. Clang understands that a .o file is already an object file and passes it on to the linker.
If you realy want to invoke ld on your own then start with clang++ -v main.cpp. The -v switch let clang print the invocation command for ld which e.g., looks like this:
/usr/bin/ld" -z relro --hash-style=gnu --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../.. -L/data/home/user/bin/../lib -L/lib -L/usr/lib /tmp/test-574b88.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o
on my Ubuntu 14.04 LTS.

is_trivially_copyable/constructible etc support of clang++ and g++

iso 20.9.4.3 Type Properties [meta.unary.prop] are not fully supported by g++'s libstdc++-v3 ; e.g.:
wget -O - https://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/include/std/type_traits 2>/dev/null | grep "still unimplemented"
// is_trivially_copyable (still unimplemented)
/// is_trivially_constructible (still unimplemented)
/// is_trivially_default_constructible (still unimplemented)
/// is_trivially_copy_constructible (still unimplemented)
/// is_trivially_move_constructible (still unimplemented)
/// is_trivially_assignable (still unimplemented)
/// is_trivially_copy_assignable (still unimplemented)
/// is_trivially_move_assignable (still unimplemented
and thus, at least as far as I understand it, clang builds based on gcc installations will inherit this lack of implementation; at least the
clang version 3.5.0 (212792)
I built just some hours ago with
g++ (Debian 4.8.3-3) 4.8.3
(but which somehow uses gcc-4.9 includes nevertheless) does not support those type traits mentioned.
But somehow Coliru
http://coliru.stacked-crooked.com/
has a clang installation, which, if invoked with
clang++ -std=c++11 -stdlib=libc++ -O2 -Wall -Wextra -pedantic -pthread -pedantic-errors main.cpp -lm -lsupc++ && ./a.out
compiles e.g. this
http://en.cppreference.com/w/cpp/types/is_constructible
example without complaints.
So there must be method to compile or setup clang, at least on Linux with headers which support also those type traits yet unimplemented by libstdc++.
In addition, llvm has this
http://libcxx.llvm.org/type_traits_design.html
summary compiled, but I have no clue how to use those "__" intrinsics; they apparently do neither live in std:: nor ::;
--
So - how to setup or configure recent llvm/clang on Linux so that clang++ has the most of those set of type traits available?
Addendum in respose to a comment
clang++ -std=c++11 -stdlib=libc++ -O2 -Wall -Wextra -pedantic -pthread -pedantic-errors test_type_traits.cxx -lm -lsupc++
test_type_traits.cxx:1:10:
fatal error: 'iostream' file not found
#include
^
1 error generated.
One simply has to install libc++ completely
Here it is
http://libcxx.llvm.org/
That built and installed like a charm and now clang indeed has those type traits when invoked like
clang++ -std=c++11 -stdlib=libc++ <other arguments>

Problems with creating a CUDA shared library and libpthread

I am currently trying to create a library with CUDA routines but I am running into trouble. I will explain my problems using a rather minimal example, my actual library will be larger.
I have successfully written test.cu, a source file containing a __global__ CUDA function and a wrapper around it (to allocate and copy memory). I can also successfully compile this file into a shared library using the following commands:
nvcc -c test.cu -o test.o -lpthread -lrt -lcuda -lcudart -Xcompiler -fPIC
gcc -m64 -shared -fPIC -o libtest.so test.o -lpthread -lrt -lcuda -lcudart -L/opt/cuda/lib64
The resulting libtest.so exports all my needed symbols.
I now compile my purely C main.c and link it against my library:
gcc -std=c99 main.c -o main -lpthread -ltest -L.
This step is also successful, but upon executing ./main all CUDA functions that are called return an error:
test.cu:17:cError(): cudaGetDeviceCount: [38] no CUDA-capable device is detected
test.cu:17:cError(): cudaMalloc: [38] no CUDA-capable device is detected
test.cu:17:cError(): cudaMemcpy: [38] no CUDA-capable device is detected
test.cu:17:cError(): cudaMemcpy: [38] no CUDA-capable device is detected
test.cu:17:cError(): cudaFree: [38] no CUDA-capable device is detected
(Error messages are created through a debugging function of my own)
During my initial steps I encountered the exact same problem, as I was directly creating an executable from test.cu, because I forgot to link against libpthread (-lpthread). But, as you can see above, I have linked all source files against libpthread. According to ldd, both libtest.so and main depend on libpthread, as it should be.
I am using CUDA 5 (yes, I do realize it is a beta) with gcc 4.6.3 and nvidia driver version 302.06.03 on ArchLinux.
Some help in solving this problem would be more than appreciated!
Here's a trivial example...
// File: test.cu
#include <stdio.h>
__global__ void myk(void)
{
printf("Hello from thread %d block %d\n", threadIdx.x, blockIdx.x);
}
extern "C"
void entry(void)
{
myk<<<1,1>>>();
printf("CUDA status: %d\n", cudaDeviceSynchronize());
}
Compile/link with nvcc -m64 -arch=sm_20 -o libtest.so --shared -Xcompiler -fPIC test.cu.
// File: main.c
#include <stdio.h>
void entry(void);
int main(void)
{
entry();
}
Compile/link with gcc -std=c99 -o main -L. -ltest main.c.

Resources