Having transitioned to OS X Mavericks and XCode 5.0.1, I can no longer gracefully link compiled C files (output from gcc) to a C++ project (output from g++).
The offending pair of commands produced from my makefile are:
gcc `pkg-config --cflags glib-2.0` -g -Wall -O3 `pkg-config --cflags flann` -c -o vec.o vec.c
g++ `pkg-config --cflags glib-2.0` -g -Wall -O3 -stdlib=libstdc++ -lstdc++ layoutquality.cpp vec.o `pkg-config --libs glib-2.0` -L/usr/local/Cellar/flann/1.8.4/lib -lflann -o layoutquality
To which the linker complains:
Undefined symbols for architecture x86_64: "load_dmat(char const*)", referenced from: _main in layoutquality-I8HOqy.o ld: symbol(s) not found for architecture x86_64
Where load_dmat
is just a function in the file vec.c . If I replace the gcc
with g++
in the first line, then everything compiles and links fine, but clang says:
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
Is there an inoffensive, non-deprecated way of compiling and linking these? Linking with g++
together with object files from gcc
worked fine before I upgraded to OS X Mavericks and the new command line tools. Any insight into what changed and how to go forward would be great, thanks.
Adding a "-x c" (without quotes) before "vec.c" should fix it.
If you compile multiple .c/.cpp files in the same line you can use "-x c" or "-x c++" before each list of C or C++ filenames to switch context appropriately. For example:
g++ -x c alpha.c beta.c -x c++ gamma.cpp
Here's an example Makefile
that let us use C++
code/function in a C
program.
CC=clang
CXX=clang++
CFLAGS=-Wall -g
CXXFLAGS=-Wall -g -std=c++11 -I.
DEPS=CPP.h
OBJ=main.o CPP.o
RM=rm -f
# compile only, C source
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
# compile only, C++ source
%.o: %.cpp $(DEPS)
$(CXX) -c -o $@ $< $(CXXFLAGS)
# link
main: $(OBJ)
$(CXX) -o $@ $^ $(CXXFLAGS)
clean:
$(RM) $(OBJ)
As you can see, we generate our objects separately using CXXFLAGS
and CFLAGS
in two separate calls to the compiler. In the context of Mac using Xcode's clang, clang (CC
) and clang++ (CXX
) are actually the same thing. Only the differing flags matter. I am just being pedantic by stating the definitions of CC
and CXX
in the above example Makefile
.
Once the object files are generated, we are good to go to link them together.
Note however that you have to do one extra step to make your C++
code usable by the C program.
In CPP.h
in this example, you have to explicitly use extern "C"
to specify linkage for your C++
code for use by C
.
For example, like this:
#ifdef __cplusplus
extern "C" {
#endif
double timesTwo(double number);
#ifdef __cplusplus
}
#endif
The preprocessor macros #ifdef __cplusplus
and #endif
are to make sure that our header file won't cause C-mode compilation errors and is only in-effect during C++-mode compilation.
This complete example comprises only 4 files.
The Makefile
source and CPP.h
are explained above.
For a complete understanding, I am including main.c
and CPP.cpp
here as well.
main.c
:
#include <stdio.h>
#include "CPP.h"
int main()
{
printf("Running main.c\n");
double ans = timesTwo(3.0);
printf("The answer from our C++ timesTwo function, when given 3.0, is %f\n", ans);
return 0;
}
CPP.cpp
:
#include "CPP.h"
double timesTwo(double number)
{
return 2 * number;
}
I trust that this explanation and example clarifies how we can set up our Makefile
, specify the #ifdef __cplusplus
preprocessor macro and extern "C"
linkage declaration to allow C++-to-C interop, and with no erroneous clang warning when we run make.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With