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++.
Related
I have a single C++14 file, my.cpp, and from within it I'm trying to use a C99 library called open62541. For the latter, both full source open62541.c/.h and a library libopen62541.a exist. In my.cpp, where I include the open62541.h, I'm using C++ specific code (e.g. iostream), so technically I'm mixing C and C++.
I can get my.cpp to compile successfully by referencing the libopen62541.a:
gcc -x c++ -std=c++14 -Wall my.cpp -l:libopen62541.a -lstdc++ -o out
This outputs no warnings, and creates an executable out.
However, if I try to compile using source code only:
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -o out
I get a lot of ISO C++ warnings (e.g. "ISO C++ forbids converting a string constant to ‘char'*") and some "jump to label" errors originating from within open62541.c, resulting in compilation failure.
I can get compilation to succeed by using the -fpermissive switch:
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -fpermissive -o out
which still outputs a lot of warnings, but creates the executable successfully. However, I'm unsure if doing this is a good idea.
Perhaps worth mentioning is that open62541.h considers C++ at the beginning:
#ifdef __cplusplus
extern "C" {
#endif
Given that .a library, which comes bundled with the open62541 library code, is supposedly built from the same source, why are the first two approaches not consistent in terms of warnings and errors generated? Why does one work and the other doesn't?
Should one method - linking .a vs referring to .c - be preferred to another? I was under impression that they should be equivalent, but apparently they aren't.
Is using -fpermissive in this case more of a hack that could mask potential problems, and should thus be avoided?
The error (and warning) you see are compilation errors (and warning) output by a C++ compiler when compiling C code.
For instance, in C "literal" has type char[] while in C++ it has type const char[].
Would you get a C++ compiler build libopen62541.a from open62541.c, you would see the same errors (warnings). But a C compiler might be OK with it (depending on the state of that C source file).
On the other hand, when you compile my.cpp and links it against libopen62541.a, the compiler doesn't see that offending C code, so no errors (warnings).
From here, you basically have two options:
Use the procompiled library if it suits you as is
g++ -std=c++14 -Wall -Wextra -Werror my.cpp -lopen62541.a -o out
Compile the library's code as a first step if you need to modify it
gcc -Wall -Wextra -Werror -c open62541.c
g++ -std=c++14 -Wall -Wextra -Werror -c my.cpp
g++ open62541.o my.o -o out
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -o out
This command forces the C code in open62541.c to be compiled as C++. That file apparently contains constructs that are valid in C but not C++.
What you should be doing is compiling each file as its own language and then linking them together:
gcc -std=gnu11 -Wall -c open62541.c
g++ -std=gnu++14 -Wall -c my.cpp
g++ -o out my.o open62541.o
Wrapping up those commands in an easily repeatable package is what Makefiles are for.
If you're wondering why I changed from the strict -std=c++14 to the loose -std=gnu++14 mode, it's because the strict mode is so strict that it may break the system headers! You don't need to deal with that on top of everything else. If you want a more practical additional amount of strictness, try adding -Wextra and -Wpedantic instead ... but be prepared for that to throw lots of warnings that don't actually indicate bugs, on the third-party code.
I want to share my project which was written in C/C++ (Linux environment gcc/g++ compiler) as shared library/static library without actually sharing the source code. So that other users can use my project without actually knowing my source code. Can anyone tell how do I share it as .so/.a format?
Suppose, my project looks like:
main.cpp,
source1.cpp,
source2.cpp,
source3.cpp,
head1.h,
Makefile
How can I share this project by hiding the source code of the files source1.cpp, source2.cpp and source3.cpp and making these as shared library/static library. main.cpp file contains the main() function. What is the detailed procedure?
PS: I am a novice in shared library/static library.
Suppose you have the following source file:
mylib.c:
#include <stdio.h>
void my_print(int i)
{
printf("i=%d\n", i);
}
The public header for this would be:
mylib.h:
#ifndef MYLIB_H
#define MYLIB_H
void my_print(int i);
#endif
You could then build the library like this:
gcc -g -Wall -Wextra -c mylib.c
gcc -g -Wall -Wextra -shared -fPIC -o libmylib.so mylib.o
Then you can distribute libmylib.so and mylib.h to users. Then can then use it in their code like this:
user_prog.c:
#include "mylib.h"
int main()
{
my_print(5);
return 0;
}
They would then put libmylib.so into someplace like /usr/lib or /usr/local/lib, and compile like this:
gcc -g -Wall -Wextra -o user_prog user_prog.c -l mylib
For your particular case, assuming head1.h contains the public interface and source1.cpp source2.cpp source3.cpp the library, you would compile like this:
g++ -g -Wall -Wextra -c source1.cpp
g++ -g -Wall -Wextra -c source2.cpp
g++ -g -Wall -Wextra -c source3.cpp
g++ -g -Wall -Wextra -shared -fPIC -o libmylib.so source1.o source2.o source3.o
You need to create object files from your source files. Then create static and/or shared libraries. You will need to provide a header file for use with your library. And note that your library must NOT contain main().
See detailed instructions for gcc
Ofcourse you can. Simply supply the people with the library file and the header files corresponding to the source files used to build the library.
I have been using C to code for sometime and I had no issues in compiling and linking my code to archive libraries (.a files). However, now I need to switch to C++ and doing so, I have to use g++ instead of cc for linking and compiling.
Using C, first thing to do was compiling the source and creating the object file and then linking it to the library using the same command but without the -c option:
cc -c -ggdb -Wall -Werror -I.. test.c -o test.o
cc -o test -ggdb -Wall -Werror test.o ../libpmem/libpmem.a
As I think the same procedure should be done for doing the same thing with g++, I tried to change the compiling and linking phase as follow:
g++ -c -ggdb -Wall -Werror -I.. test.c -o test.o
g++ test.o -I.. -L/path/libpmem -lpmem -o test
Although both sets should do the same thing, I always get an error while trying to link using g++. Here is the error message:
test.o: In function `main':
/path/test/test.c:5: undefined reference to `pmem_msync_mode()'
collect2: ld returned 1 exit status
make: *** [all] Error 1
There must be something wrong with the linking phase as the method definition must be found in the library file (just as the cc linker can find the definition and do the linking without any problem).
I also tried to do both linking and compiling using a single g++ command, but no matter what I do, I always get the same error. Any idea how can I fix this?
you probably have some sort of name mangling problem...
since it looks like that is declared in a c library there should already be some sort of
#ifdef __cplusplus
extern "C" {
#endif
int pmem_msync_mode();
#ifdef __cplusplus
}
#endif
but if there isn't in the library header you may have to do something like;
extern "C" {
#include <pmem.h>
}
See http://www.cplusplus.com/forum/general/1143/
You need to tell the compiler that the code is compiled as C
I am assuming that the pmem library is compiled and linked as C code.
C and C++ have different conventions for how they store the names of functions in binary format. See http://en.wikipedia.org/wiki/Name_mangling for a reference.
To solve your problem, probably the solution is to:
extern "C" {
#include <pmem.h>
}
When the C++ compiler imports the function declarations from the header, without external C linkage being specified, it expects the binary it links against to have the associated functions' representations in a different format, namely whatever format your C++ compiler mangles function names to.
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
I have a dependancy library (libfcgi) that I compiled with g++ (GCC v4.4 MinGW) using the following calls:
g++ -Iinclude -c -O2 *.c
ar rcs ../libfcgi.a *.o
Now, my main project is built like so:
g++ -Idependancies\libfcgi\include -Ldependancies -O2 -lfcgi *.cpp
g++ apparently finds libfcgi.a, but yet it fails to link to the following references:
'FCGI_printf'
'FCGI_Accept'
In the libfcgi sources, these functions are defined as follows:
#ifdef __cplusplus
extern "C" {
#endif
//...
DLLAPI int FCGI_printf(const char *format, ...);
DLLAPI int FCGI_Accept(void);
//...
#ifdef __cplusplus
}
#endif
where DLLAPI is nothing (as it isn't compiled as a shared library) and __cplusplus is defined (g++).
Looking at libfcgi.a, those functions are exported as '_FCGI_Accept' and '_FCGI_printf', so with an underscore in front. That's what seems to hinder g++ to find them.
I thought using export "C" would suffice to link to a C function in C++, so what am I doing wrong?
Thanks :)
If you have the same extern "C" definitions in your .cpp sources, then I think your problem is that the -lfcgi should follow the *.cpp in your command line:
g++ -Idependancies\libfcgi\include -Ldependancies -O2 *.cpp -lfcgi
In your main-project, you tell the compiler to link C-functions, due to the extern "C". It therefore expects unmangled symbol-names. You should therefore compile the fcgi-library with the C compiler, not the C++ compiler.