Apologies for such a beginner question, but I have been stuck on making Makefile work on my c++ files for quite a while
My makefile contains two .cpp files and one .h files and are as follows
example.o: example.cpp example.h
g++ -c example.cpp
main.o: main.cpp example.h
g++ -c main.cpp
main: main.o example.o
g++ main.o example.o -o main
and it outputs the following error when I try to make main
Undefined symbols for architecture x86_64: *(with large pieces of code)*
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [main] Error 1
However, it works perfectly fine when I just do a compilation of the program by using
g++ main.cpp example.cpp -o main
Is there any reason why Makefile doesn't work but just compiling works? Thanks a lot for any replies!
Please show the output of make including the compiler lines that were invoked, not just some of the error output. Also it would be helpful if you provided at least SOME of the symbols that were not found so we could get an idea of what is missing.
There is no reason from the info you've provided why this should happen, so the cause must be related to some detail that you haven't provided.
One difference between the command line and the makefile is that the makefile builds object files then turns them into an executable, while the command line simply compiles the sources directly into an executable.
Maybe you have some .o files lying around from a different compilation? If you use rm -f *.o before you run make do you still see the same errors?
Also, it's a little odd that you're invoking g++ but the error output says clang which is a completely different compiler. Are you trying to build on MacOS? You should always provide your operating system info. If you're building on MacOS you should just use clang directly, unless you've explicitly install GCC and want to use that.
Related
I have the following C++ code in a file called helloworld.cpp:
#include<iostream>
int main()
{
std::cout << "Hello, World!\n";
}
I would like to compile this manually so I can really understand how the compilation steps work with gcc, namely:
Preprocessing
Compilation
Assembly
Linking
This article gives some useful information about how to break up the compilation steps. And so I came up with the following:
Preprocessing
cpp helloworld.cpp > helloworld.i
Compilation
g++ -S helloworld.i
Assembly as -o helloworld.o helloworld.s
Linking
ld -o helloworld helloworld.o
Everything seems to work except for the last step, as outlined by the article:
ld -o hello hello.o ...libraries...
The libraries argument above is a long list of libraries that you need to find out. I omitted the exact arguments because the list is really long and complicated, and depends on which libraries g++ is using on your system. If you are interested to find out, you can run the command g++ -Q -v -o hello hello.cpp and take a look at the last line where g++ invokes collect2
And so I tried running g++ -Q -v -o helloworld helloworld.cpp, but the result is extremely verbose.
I'm still unsure how to complete ld such that iostream can be available to the linker when I invoke it. How can I make sure iostream is available to the linker?
I'm still unsure how to complete ld such that iostream can be available to the linker when I invoke it.
You should never use ld to link any user-level programs, only when you are linking something esoteric, like an OS kernel or a boot loader.
Instead, (for user-level program) always use appropriate compiler driver (g++ here).
While you can find out how the compiler driver eventually invokes ld internally (e.g. using strace -fe execve -s 1024 g++ ...), note that that command may change from version to version, and depends on a multitude of flags (-pie vs. -no-pie, -shared, -static etc.) and you chances of continuing to use correct ld command after a few months are nil.
Based on the comments and posted answer I realized that the blog from which I was copying those commands makes things more complicated than they really need to be for my purposes. It's definitely possible to isolate every step of the compilation process using solely the g++ command. Here's a Makefile I came up with:
all: preprocess compile assemble link
# helloworld.i contains preprocessed source code
preprocess:
#echo "\nPREPROCESSING\n"; g++ -E -o helloworld.i helloworld.cpp
# compile preprocessed source code to assembly language.
# hello.s will contain assembly code
compile:
#echo "\nCOMPILATION\n"; g++ -S helloworld.i
# convert assembly to machine code
assemble:
#echo "\nASSEMBLY\n"; g++ -c helloworld.s
# links object code with the library code to produce an executable
# libraries need to be specified here
link:
#echo "\nLINKING\n"; g++ helloworld.o -o test
clean:
#find -type f ! -name "*.cpp" ! -name "*.h" ! -name "Makefile" -delete
Now I can compile my C++ programs in such a way that I can track whether the preprocessor, compiler, assembler or linker is generating the error.
I've been getting this undefined symbol building with this command line:
$ gcc test.cpp
Undefined symbols:
"___gxx_personality_v0", referenced from:
etc...
test.cpp is simple and should build fine. What is the deal?
Use
g++ test.cpp
instead, since this is c++ code.
Or, if you really want to use gcc, add -lstdc++ to the command line, like so:
gcc test.cpp -lstdc++
Running md5 against the a.out produced under each scenario shows that it's the same output.
But, yeah, g++ probably makes your world a simpler place.
The .cpp extension causes gcc to compile your file as a C++ file. (See the GCC docs.)
Try compiling the same file, but rename it to have a .c extension:
mv test.cpp
gcc test.c
Alternatively, you can explicitly specify the language by passing -x c to the compiler:
gcc -x c -c test.cpp -o test.o
If you run nm test.o on these C-language versions, you'll notice that ___gxx_personality_v0 is not listed as a symbol.
(And if you run the same command on an object file generated with gcc -c test.cpp -o test.o, the ___gxx_personality_v0 symbol is present.)
Just in case anyone has the same problem as me: The file extension should be a .c not a .C (gcc is case-sensitive).
Had the same problem, but a different solution:
C++ code in static library getting linked, and being referenced by a .m file. Renaming the .m file to .mm fixed the issue.
I have a main.cpp file in a directory called test that has an
#include "INIReader.h"
The structure of the files is like below
---/test/main.cpp
---/inih/ini.h
ini.c
---/inih/cpp/INIReader.h
INIReader.cpp
INIReader.cpp has these includes
#include "../ini.h"
#include "INIReader.h"
I am trying to compile main.cpp in one line with
g++ -o test -Wall -I../inih/cpp main.cpp
but it is not working. Errors like
> Undefined symbols for architecture x86_64:
>... REFERENCES TO stuff in INIReader ...
>ld: symbol(s) not found
> for architecture x86_64 clang: error: linker command failed with exit
> code 1 (use -v to see invocation)
show up.
Right now I am compiling by running the commands and it will work.
> g++ -c -Wall ../inih/cpp/INIReader.cpp
> g++ -c -Wall ../inih/ini.c
> g++ -c -Wall -I../inih/cpp main.cpp
> g++ -o configtest main.o INIReader.o ini.o
I thought that the g++ compiler will look for each #include in each of the default include directories and the passed -I directory and do not know why the above one liner does not work. Will g++ "follow" includes in all files like the ./ini.h? I have not been able to find a good resource for learning this.
How can I combine these command into one line like the previous command? Thanks.
Edit:
I have looked at the "duplicate" question but not understand how it relates to my problem. I am trying to find a good resource for learning how to "include" correctly with g++ and know why my current one liner does not work.
It is not a problem in the code, as compiling and then linking one by one is successful!
Duplicate question was similar, but did not cover including files in other directories.
The error you are getting is coming from the linker step, not the compiler step. It doesn't have anything to do with your includes. You need to tell the linker all the files required to make the target binary. As has been said in this answer, which may be the question this was previously closed as a duplicate of, you just need to list all of the cpp files after main in the command line. So for yours, the command line should be something like:
g++ -o configtest -Wall -I../inih/cpp main.cpp ../inih/cpp/INIReader.cpp ../inih/ini.c
Once you start compiling all of the files in one step, you may have to add an extra include instruction to find header files in different paths, so your command line might need to be:
g++ -o configtest -Wall -I../inih/cpp -I../inih main.cpp ../inih/cpp/INIReader.cpp ../inih/ini.c
But that depends how you're including your headers from your source files...
I have a requirement of creating a C++ program which exposes certain functions through HTTP. For that reason I was trying to use libmicrohttpd for the same. Now this library is written in C. However I am kind of new to C++ and am trying to compile this C and C++ code given here. (Which can be git cloned from here)
Now I need help in understanding how g++ may be used to compile a program which is not written completely in C++. And/or how to compile the above linked code.
PS: Working in linux
And finally if someone can point to an easier alternative than libmicrohttpd - I am all ears.
Edit to Edit:
Finally got it working. Compiled the individual cpp files with gcc and then linked everything using g++. I have no clue how this came to work, maybe some one can reply below.
I have made the following script to compile and link:
LOC="path/to/directory"
gcc -c httphandler.cpp -o httphandler.o -I $LOC
gcc -c strutil.cpp -o strutil.o -I $LOC
gcc -c api.cpp -o api.o -I $LOC
gcc -c executor.cpp -o executor.o -I $LOC
g++ -o out httphandler.o strutil.o api.o executor.o -lmicrohttpd -lboost_regex
But in the final step I am getting the following error:
/usr/bin/ld: strutil.o: undefined reference to symbol '__cxa_free_exception##CXXABI_1.3'
/usr/bin/ld: note: '__cxa_free_exception##CXXABI_1.3' is defined in DSO /usr/lib/x86_64-linux-gnu/libstdc++.so.6 so try adding it to the linker command line
/usr/lib/x86_64-linux-gnu/libstdc++.so.6: could not read symbols: Invalid operation
What gives?
For starters, don't compile the C code with g++, use gcc instead. Then just include the header file and use the functions normally. When linking don't forget to link with the object file(s) generated from compiling the libmicrohttpd source file(s).
I wrote the Makefile for an easier way to run the unit tests (the default target is test). The directories structure is as follows:
lib - google c++ test framework
src - source files
test - unit tests
In src I have the files a.h, a.cc, b.cc (which holds main) and I want to test class A() which is defined in a.h. All in all, because the order of linking is:
g++ -Wall -c -o obj/src/a.o src/a.cc
g++ -Wall -c -o obj/src/b.o src/b.cc
g++ -o all obj/src/a.o
I get the error:
(.text+0x18): undefined reference to main'
collect2: ld returned 1 exit status
make: *** [all] Error
even though I don't actually need a main() defined in src since I already have a main() defined in test which runs the unit tests.
I don't understand very well what you want to do, but if your main is in, say, test.o, you need to specify that in you linking line. For example:
g++ -o all obj/src/a.o test.o
When you say
g++ -o all obj/src/a.o
g++ thinks you've asked it to build a executable, and accordingly is looking for the entry point. Presumably you meant to ask it for something else (a library, maybe?).
Even though it doesn't solve your current problem, it might be helpful to know that you are re-engineering automake. You shouldn't be writing Makefiles for C or C++ projects by hand nowadays.