Linking C++ object file with clang (not clang++)

Hi all,


I am trying to build a library including C and C++ object files, but I need to perform the link with Clang (not Clang++). The basic reason of this is that my real use case also uses Fortran object files, so I never link my libraries with the C++ compiler.


The typical command for building a library is:

$(CC) -shared hellocpp.o -o libhellocpp.dylib


However, since hellocpp.o is a C++ object file, the link fails because of missing C++ symbols. Using GNU g++ compiler, the solution is straightforward, because g++ can tell me where its libstdc++.so is, e.g.

STDCXX_LIB = $(shell g++ -print-file-name=libstdc++.so)
gcc -shared hellocpp.o -o libhellocpp.so $(STDCXX_LIB)


Unfortunately this scheme fails with clang and clang++. The option -print-file-name is documented but not implemented. In other words, this fails:

clang++ -print-file-name=libstdc++.dylib


Worse, it seems that I have to link my objects files against libc++.1.dylib, not libstdc++.dylib, i.e. only this link command is successful:

clang -shared hellocpp.o -o libhellocpp.dylib /usr/lib/libc++.1.dylib

But my worry is that this explicit naming is full of assumption (C++ library name and location) and is not portable.


In summary, my need is:

- linking C++ objects files with clang (not clang++),

- no assumption on the location (because I may use a compiler from a non standard location),

- if possible no assumption on the library name.


And my question is: can I ask clang++ what is the C++ library path to be given to clang?


Here is a short hello-world example (use "make hello" or "make clean"):


$ cat helloc.c
#include<stdio.h>
int main()
{
    printf("Hello from C.\n");
    hellocpp();
    printf("Done C.\n");
}


$ cat hellocpp.cpp
#include <iostream>
extern "C" void hellocpp()
{
  std::cout << "Hello from C++.\n";
  std::cout << "Done C++.\n";
}


$ cat Makefile
CC = clang
CXX = clang++
SHLIBEXT = dylib

# Option 1: giving nothing (link fails)
# STDCXX_LIB =

# Option 2: asking for libstdc++.dylib location (not implemented)
STDCXX_LIB = $(shell $(CXX) -print-file-name=libstdc++.$(SHLIBEXT))

# Option 3: explicit path (strong assumptions)
# STDCXX_LIB = /usr/lib/libc++.1.dylib

%.o: %.c
        $(CC) -c $< -o $@

%.o: %.cpp
        $(CXX) -fPIC -c $< -o $@

# Link library with gcc (while object file contains C++ code)
libhellocpp.$(SHLIBEXT): hellocpp.o
        $(CC) -shared hellocpp.o -o $@ $(STDCXX_LIB)

hello: helloc.o libhellocpp.$(SHLIBEXT)
        $(CC) helloc.o -o $@ -L. -lhellocpp $(STDCXX_LIB)

clean:
        rm -f *.o *.$(SHLIBEXT) hello

Try a link command with clang and --verbose and then try that same command with clang++ and --verbose. You'll see the sole difference is that clang++ passes "-lc++" to the linker.


So, first, why really can't you use clang++ to link? There's literally no difference from using clang other than that it will automatically provide the proper C++ library. "clang" and "clang++" are literally the same executable. "clang++" is just a symbolic link pointing to "clang". Clang just checks the name used to invoke it to tweak its behavior. (Note that you will be misled if you look at the binaries in /usr/bin. Those aren't the real executables, they are trampolines that forward to the real executables in Xcode or the Command Line Tools. Use "xcrun -f clang" and "xcrun -f clang++" to find the real executables and examine those to see what I'm talking about.)


To my knowledge, there's nothing about linking with Fortran-originating object files that would prevent successfully using clang++. Have you actually tried?


And, if you really want to use clang, you could just pass -lc++ yourself.

Our libraries are actually a mixture of C, C++ and Fortran files. The link is performed with gfortran (which takes care of its libgfortran), because we have by far more Fortran sources, and marginal (but still) use of C++. No problem with libc. And for C++, we used to use this "g++ -print-file-name" trick.


As far as I know, Xcode does not offer a Fortran compiler, so we are using MacPorts one. 2 possibilities:

- use MacPorts (GNU) gfortran + gcc + g++: this is a consistent set of compilers and the "g++ -print-file-name" trick works.

- use MacPorts (GNU) gfortran and Apple clang/clang++: one of them has to do the link correctly with all the compiler libraries.


Note that your "-lc++" does not help as it won't be recognized by the MacPorts (GNU) gfortran (used for the link, as explained above). We need the full path to the correct C++ library.


Or, do you discourage mixing clang/clang++ and Macports (GNU) gfortran object files in the same library?

Linking C&#43;&#43; object file with clang (not clang&#43;&#43;)
 
 
Q