Unable to compile simple C++ program with embedded Julia 1.0

I’m trying to build a simple embedding example in C++. I’m working on a CentOS 7 machine with GCC 4.8.5. I am using the generic Linux binaries from the downloads page for Julia 1.0.

I get a bunch of errors like the following:

/software/x86_64/julia/julia-1.0.0/lib/julia/libLLVM-6.0.so: undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::replace(unsigned long, unsigned long, char const*, unsigned long)@GLIBCXX_3.4.21'

Any idea what I am doing wrong?

Here’s my C++ file:

#include <julia.h>

int main(int argc, char *argv[])
{
    jl_init();
    jl_eval_string("println(\"Hi!\")");
    jl_atexit_hook(0);
    return 0;
}

And here’s my makefile:

JL_SHARE := $(shell julia -e 'print(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia"))')
CFLAGS   += $(shell $(JL_SHARE)/julia-config.jl --cflags)
CXXFLAGS += $(shell $(JL_SHARE)/julia-config.jl --cflags)
LDFLAGS  += $(shell $(JL_SHARE)/julia-config.jl --ldflags)
LDLIBS   += $(shell $(JL_SHARE)/julia-config.jl --ldlibs)
CC := gcc
CXX := g++

.PHONY: all
all: main

main: main.c makefile
	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) -o main main.c

.PHONY: clean
clean:
	$(RM) main

It works fine if I instead build it as a C program.

1 Like

You need to be careful with using the CFLAGS as given by julia-config.jl when compiling a C++ file as some of the flags might not be valid. For example, julia-config.jl --cflags gives me a -std=gnu99 flag, which is not valid for C++. In order to compile a C++ program, this flag has to be removed. Something similar might causing your problem.

Thank you for the idea, but unfortunately that didn’t fix it.

Have a look at PackageCompiler, section “Static Julia Compiler”, Julia 1.0 support is WIP but already usable.

Looks like an ABI mismatch? There is a compile flag you can use to choose which ABI to use.

I see g++'s -fabi-version=n option, though I’m not sure what value to use for n.

Your comment helped me know what to search for, and I’ve now also found mention of -D_GLIBCXX_USE_CXX11_ABI=0. Though doing that didn’t help…

I don’t have a system with such an old stdlibc++ to test and the error message is quite strange so I’ll have to guess…

The error comes from the LLVM ships with julia to not able to find the right symbol. Assuming the julia runs fine the stdlibc++ julia need should be fine (i.e. it was not missing from your download). Since compiling with C also didn’t error it suggests that the linker does not have issue with it either.

As for linking as c++ program, there’s one difference that I can think of that could lead to this problem, which is that c++ programs are automatically linked to libstdc++. It’s then possible that the automatically linked one is the system one that is too old which make the linker unhappy about the llvm’s requirement.

If this is indeed the issue, you need to convince g++ to find the right libstdc++ or at least avoid the wrong one. It’s a very unusual thing to do and as I said I don’t have a setup to test so you’ll need to figure out what to do on your own. A few things that you might find useful are,

  1. You can stop the compiler from linking libstdc++ by using gcc or ld as linker instead of g++ (requires you to compile .c to .o with g++ first as a separate step)
  2. You can use -nodefaultlibs to disable libstdc++ (there could be option for libstdc++ directly)
  3. You may be able to specify the path of libstdc++ directly (Ref gcc - C++ - g++ links against wrong stdlibc++ - Stack Overflow and c++ - Forcing or preventing use of a particular minor version of libstdc++ - Stack Overflow)
  4. If you are brave enough, you could also overwrite your system libstdc++ with the newer one shipped with julia…
5 Likes

-D_GLIBCXX_USE_CXX11_ABI=1 since julia is probably using the newer one ( version 1 ) and default for gcc 4.8.5/centos 6 is 0. If this doesn’t solve it I can find my old julia embedded makefile and see what I have in there. You may need to set your LD_LIBRARY_PATH to point a compatible libstdc++.so. I’m on CentOS 6 at work as well.

1 Like

Thank you for the thorough answer and suggestions!

I tried using the -nodefaultlibs option. It gave me the same error. Then I went inside the lib/julia directory of the generic Linux binaries, and found that there isn’t a symlink for libstdc++.so, there’s just the one versioned file. After adding that symlink, I was able to compile.

Is that a mistake in the Julia 1.0 binaries?

The julia binary has it’s RPATH set to point to it’s lib directory.
$ readelf -d julia
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/…/lib]

Then libjulia.so has it’s RPATH set to look in lib/julia. Which holds the libstdc++ it needs.

Did you try using gcc as a linker instead? I feel like that should work without the symlink.

Hard to say. None of that is needed for execution and you only hit an issue since you are trying (indirectly) to link to it. However, at least in this case, you are not actually linking to it, it’s just llvm that needs it, which means that it’s not a super unambiguous argument for shipping the dev file (symlink). I don’t really see what’s bad about shipping it either though.

You should try building with D_GLIBCXX_USE_CXX11_ABI=1
Pretty sure gcc 4.8.5 on your CentOS is going to default to ABI=0 ( the older one ). Julia’s libs were very likely built with ABI=1 ( that’s what the __cxx11 namespace indicates ). Hopefully this will do it. If you do link with any other ABI=0 libs you’d need to rebuild those with ABI=1.

https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html

During runtime you may need to set the LD_LIBRARY_PATH environment var so it will pick up the ABI=1 libs before your default system ABI=0 libs, but I’m not sure if that is necessary after setting the correct ABI. Alternatively ( maybe more recommended way? ) is to set the RPATH. Or a symlink can work as well, which is what you are doing.

Note that

  1. the error does not come from his program
  2. this flag does not change the behavior of the compiler, only the stdlib
  3. the error has a cxx11 name, meaning the new abi is used, not the other way around.
  4. his program does not use any c++ features, in particular, not any std::string.

And a symlink like that will never have any effect at runtime. (unless loaded by dlopen, which isn’t the case here)

Well, I’m not totally clear on the relationship between linking a .so and runtime loading of the .so. I’m also not clear on the what the symlink is doing in this case.
I do know that building a program with gcc 4.8.5 on CentOS 6 requires you to set the ABI=1 if you are linking with any libs that are built with ABI=1. Which is the maybe the case here ( non-standard CentOS 6 environment vs CentOS 7 ).

Symptomatically, if I see that exact error, I set the ABI to 1 and it fixes it. Possibly also setting the LD_LIBRARY_PATH.

No it’s not…

He said he’s working on a CentOS 7 machine with gcc 4.8.5

… I mean he is not linking to a library guilt with the new option.

Sorry, I made a mistake, and you are right.

I was using g++ to link, and I was passing -nodefaultlibs, but I also mistakenly put -lstdc++ in my command. If I remove -lstdc++ from the linking command, I don’t need the symlink.