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.
Makefile
main.c
CPP.h
CPP.cpp
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.
Most probably you are a victim of Name mangling. To avoid name mangling in C++, use extern "C" around declarations, like:
#ifdef __cplusplus
extern "C" {
#endif
void load_dmat(char const*);
#ifdef __cplusplus
}
#endif
Related
I've been given a package of files (one .cpp, and some .c and .h) and want to make some modifications. But right now I'm just trying to get the original version to compile (in Linux).
Here's a (really) minimal working example:
mainfile.cpp
extern "C"{
#include "auxfile.h"
}
int main(int argc, char * argv[]){
getfoo(temperature);
return 0;}
auxfile.h
#define PUBLIC
#define PRIVATE static
extern int temperature;
int getfoo( int inputint);
auxfile.c
#include "auxfile.h"
int temperature = 37;
PUBLIC int getfoo( int inputint){
return 7;
}
When I type
g++ mainfile.cpp
I get
mainfile.cpp(.text+0x11): undefined reference to `temperature'
mainfile.cpp(.text+0x18): undefined reference to `getfoo'
collect2: ld returned 1 exit status
For what it's worth, I've looked through numerous "undefined reference" questions and spent dozens of hours working on my own. The above code presents the essence of the problem. Any help would be massively appreciated. Thanks.
At the time of linking, all symbols (except those for dynamic linking, aka shared libraries) have to be defined. To create an object file with possibly unresolved symbols for later linking, there is the -c flag, that means just compile, do not link.
So, the following would work:
g++ -c -omainfile.o mainfile.cpp
gcc -c -oauxfile.o auxfile.c
g++ -o mainfile mainfile.o auxfile.o
Only the last line actually invokes the linker and as you have both object files, all symbols are found.
Just for completeness, in a real-world scenario you'd handle compiling and linking using make. Create a Makefile with the following contents:
OBJS:= mainfile.o auxfile.o
all: mainfile
# $# means what to build (in this case "mainfile"), $^ is replaced by all
# dependencies (here the contents of the variable OBJS)
mainfile: $(OBJS)
g++ -o$# $^
# pattern for *.cpp -> create a *.o file with same name using g++
%.o: %.cpp
g++ -c -o$# $<
# the same for *.c, but using gcc here
%.o: %.c
gcc -c -o$# $<
clean:
rm -f $(OBJS)
# "PHONY" are targets, that are not actually the names of output files
.PHONY: all clean
Then just type make and see the "magic" happening. Of course this is just for starters, no dependencies are tracked etc...
Let's say, compiling hello.c requires car.c and water.c.
But main.c requires hello.c.
When I say requires, I mean that the compiled output would differ if the things it requires is modified in any way.
So, if car.c or water.c is changed, then hello.c would need recompiling.
Then, would this be the correct Makefile?
main: main hello.o
gcc main.c hello.c -o main
hello.o: water.c, car.c
gcc water.c car.c -o hello.o
Otherwise, if it's not correct, can someone explain to me why it is wrong and give me an example?
Thank you!
Let's say, compiling hello.c requires car.c and water.c. But main.c requires hello.c.
This statement doesn't make a lot of sense. The only thing it could mean is that either these aren't C or C++ source files, rather some other language that uses these names confusingly, or they contain #include directives that include those other files.
In that latter case (which is rare, and a poor design), there's no need to specify the included files on the command line, since gcc will include them for you. You just need to specify the dependencies in the Makefile:
main: main.c hello.c car.c water.c
gcc -o main main.c
since main.c has #include "hello.c" and hello.c has #include "car.c" and #include "water.c", only the one compile gets everything.
If these are some other language, and you mean something completely different, its likely that gcc can't understand (or compile) them at all...
What you're doing is a little strange, but I guess not incorrect. Don't have a recursive dependency on main and compile hello.o as an object file.
main: main.c hello.o
gcc main.c hello.o -o main
hello.o: hello.c water.c car.c
gcc hello.c water.c car.c -c hello.o
I would re-write it as:
SRC := hello.c main.c water.c
OBJS := $(patsubt %.c,%.o,$(SRC))
main: $(OBJS)
$(CC) -o $# $^
This makefile works because there is an implicit rule for compiling C files. This will mean that when $(OBJS) is expanded to hello.o, main.o, and water.o, each of those .o files will be built by "$(CC) -o hello.o -c hello.c".
Note that if you use the GCC -c flag to only compile the file, but not link it, you will not need to be worried that hello.c relies on car.c and water.c.
EDIT:
Note that in your original makefile, the line "main: main hello.o" is incorrect. A target cannot depend on itself.
In general, with Make, you want to specify dependencies, but not the implementation of making those dependencies, if you can help it. It is much cleaner to say "I need this" versus "do these steps". In a lot of cases, Make is smart enough that if you say "I need this," it will "do the right thing."
In your makefile there are entities of the following type:
final executable program: main
compiled objects (relocatable ELFs linked into the main executable). I can see hello.o, but I cannot find water.o, car.o and main.o (since each *.c compilation unit is generally converted by the compiler to a *.o compiled object).
the source files (compilations units): main.c, hello.c, water.c and car.c. These are used as inputs by the compiler to generate the corresponding *.o files.
So, based on the above, the appropriate Makefile would look like this (tested):
main.o:
gcc -c main.c
hello.o:
gcc -c hello.c
water.o:
gcc -c water.c
car.o:
gcc -c car.c
main: hello.o water.o car.o main.o
gcc hello.o water.o car.o main.o -o main
The shortened versioned, using makefile text functions and automatic variables (tested):
%.o:
gcc -c $(addsuffix .c, $(basename $#))
main: hello.o water.o car.o main.o
gcc $^ -o main
Another approach (tested):
SRC := hello.c water.c car.c main.c
OBJ := $(addsuffix .o, $(basename $(SRC)))
main: $(OBJ)
gcc $^ -o main
I have a project that had c files and cpp files mixed in it. The linker throws errors at me:
undefined reference to <all my functions in the c files>
After I rename all *.c files to *.cpp the errors vanish. So can't I mix those files or is this some compiler/linker options problem?
My options:
GCC C++ Compiler:
-I/usr/include/glib-2.0 -I/usr/include/gtk-2.0 -I"/myPath" -O0 -g3 \
-Wall -c -fmessage-length=0 `pkg-config --cflags glib-2.0 gtk+-2.0
GCC C Compiler:
-I/usr/include/glib-2.0 -I/usr/include/gtk-2.0 -I"/myPath" -O0 -g3 \
-Wall -c -fmessage-length=0 -std=c99 `pkg-config --cflags glib-2.0 gtk+-2.0`
GCC C++ Linker:
-L/usr/include/glib-2.0/glib `pkg-config --libs gtk+-2.0`
Since it says C++ Linker, does that mean object files from c files cannot be linked into the project (by default)?
You need to wrap the C code like so
extern "C" {
#include "sample1.h"
}
A better way to do it is like in this StackOverflow question, in the C header files.
use:
#ifdef __cplusplus
extern "C" {
#endif
At the start of all C header files.
and use:
#ifdef __cplusplus
}
#endif
At the end of all C header files.
extern "C" is one approach. The other approach, assuming your C files are of the (almost ubiquitous) sort which are already compilable as C++, is simply to coerce the compiler into treating them as C++ (which gives them the appropriate name mangling to work with your C++ files). For GCC, this is -x c++.
I'm writing a terminal based Tetris game using ncurses. I've segregated all of the ncurses code into a file called tetrisUI.c which i include a header file for in my main.c source file. When I compile all of the ncurses functions raise compiler errors. I have included ncurses.h in my source file and I'm using the -lncurses flag in gcc. I'm compiling from a makefile with the following contents:
Tetris : tetris.o main.o tetrisUI.o
gcc tetris.o main.o tetrisUI.o -o Tetris
tetrisUI.o : tetrisUI.c
gcc -std=c99 -c tetrisUI.c -lncurses
tetris.o : tetris.c tetris.h
gcc -std=c99 -c tetris.c
main.o : main.c tetris.h tetrisUI.h
gcc -std=c99 -c main.c
I was able to compile a few short test programs using ncurses just fine. This is my first attempt at using ncurses and my first significant c program (I've done a little c++ in school). I have a hunch that my problem has something to do with my makefile but I'm a noob at using those too.
Use -lncurses at the link stage not at the compile stage:
gcc tetris.o main.o tetrisUI.o -o Tetris -lncurses
You can simplify your Makefile by using default macros and rules:
CFLAGS = -std=c99 # C compiler flags
LDLIBS = -lcurses # curses
Tetris : tetris.o main.o tetrisUI.o # make does a "$(CC) $(CFLAGS) -o $# $^ $(LDLIBS)" on its own
That's all you need. The following definitions and rules can be completely omitted - make does the right thing by default:
CC = gcc # C compiler name
tetrisUI.o : tetrisUI.c tetrisUI.h # make does a "$(CC) $(CFLAGS) -o $# $<" on its own
tetris.o : tetris.c tetris.h
main.o : main.c tetris.h tetrisUI.h
A bit of explanation: $# is whatever is being built, $< is the first dependency, $^ is all of them. Judicious use of this makes for less typing (and less idiotic errors, where you add a dependency and don't process it; or omit a dependency (and thus don't redo the build if it changes)). Take a look at the make manual, if you have GNU make, its info file has lots of detailed examples and tips.
I have a cross platform program I am working on that has several files with
#ifdef WIN32
...inclues
#endif
#ifdef LINUX
..inlcudes
#endif
when I went to compile on LINUX I keep getting errors about not finding functions and such, but if i comment out the #ifdef LINUX blocks (still keeping the includes uncommented) it works, so it seams as if my define is not working properly.
This is my make file (file names changed):
CC = gcc
CPP = g++
CFLAGS = -DLINUX $(INCLUDES) -c -g -O0 -Wall -fpic
INCLUDES = -I.
LFLAGS += -fpic -shared
LFLAGS += -lpthread
CFILES = a.c b.c c.c d.c e.c f.cpp g.cpp h.cpp i.cpp
##all: $(SFILES:.s=.s.o) $(CFILES:.c=.o) $(CFILES:.cpp=.o)
## $(CPP) $(INCLUDES) $(LFLAGS) -o libclient.so.1.0 $(CFILES:.c=.o) $(CFILES:.cpp=.o)
all: $(SFILES:.s=.s.o) $(CFILES:.c=.o)
$(CPP) $(INCLUDES) $(LFLAGS) -o libclient.so.1.0 $(CFILES:.c=.o)
%.o : %.c
$(CPP) -c $(CFLAGS) $< -o $#
%.o : %.cpp
$(CPP) -c $(CFLAGS) $< -o $#
clean:
rm *.o libclient.so.1.0
Your make file actually does work for c files, but not for c++ files.
This is because you invoke your custom compile command line for c compilation but your cpp files are going directly into what is effectively your link command line which does not specify compilation flags.
First make sure you're using the proper command, so copy paste the output from Makefile and execute that from your shell (by hand).
Maybe your define is undefined along the way so, here are two approaches to find out what's wrong:
1) include #warning statement(s) within your ifdef to see if it is really a missing define:
#warning "before the define"
#ifdef LINUX
#warning "here goes the linux define"
..inlcudes
#endif
if you compile the code and don't see the warning then indeed you miss the define somewhere.
2) Check the preprocessor output. To do so send the preprocessor (use cpp not g++) output to stdout by using the -E flag. (cpp -E ....)
By looking at output you can see all code included, so you can track down in detail what code your compiler gets. I find that method of last resort usually giving most insight into
weird problems.
Change you ifdefs to
#ifdef WIN32
...inclues
#endif
#ifdef __linux__
..inlcudes
#endif
If the ifdef'ed content is UNIX rather than Linux specific use __unix__
You should be using a construct like this:
#ifdef _WIN32
// Windows specific #includes
#else
// Unix specific #includes
#endif
rather than setting yourself up to work only on Windows and Linux. The differences between Linux and other Unix systems are not worth worrying about till someone complains, but don't make life harder for yourself in advance.