Section 6.2 Exploring Separate Compilation
The file
library.cpp
below has some simple functions. The code does not depend on any other code (no includes). However, there is no main function. This means that if we try to compile and link the code into a program, using a recipe like the one below, the build will fail.
$ g++ library.cpp -o program.exe
library.cpp
- attempt to compile and linkIf you try out the ActiveCode, you should get an error about an
undefined reference to main
We canβt link that file into a full program because there is no main function. But it is possible to just compile the code. To do that with g++, we can use the
-c
flag which tells the compiler to just compile the file and not link it:
$ g++ -c library.cpp -o library.o
This recipe will successfully build. But there is no program to run:
library.cpp
- set to just compile and not link or executeThe
main.cpp
below has a different problem. Although it has a main function, it tries to call doubleValue
, which is not declared. So if we try to compile it, we get an error:
$ g++ -c main.cpp -o main.o
main.cpp
- set to just compile and not linkmain.cpp
(with declaration) - set to just compile and not linkThe declaration promises the compiler that
doubleValue
exists somewhere. The compiler goes ahead and builds the code in main
by relying on the promise. (See SectionΒ 5.8 for a reminder of the difference between declaring and defining a function.)
Although we can compile
main.cpp
now, if we try to link it into a program, we will get an error because the linker does not know where to find the definition of doubleValue
. This time we will try building without the -c
flag:
$ g++ main.cpp -o program.exe
This recipe tells the compiler that we want to both compile
main.cpp
and try to link it into a full program.
main.cpp
(with declaration) - set to compile and linkThat recipe should result in an error like this:
/usr/bin/ld: /tmp/ccoUEcGg.o: in function `main': test.cpp:(.text+0x19): undefined reference to `doubleValue(int)' collect2: error: ld returned 1 exit status
ld
is the linker. The final line tells us that the linker had an error. Above that is the error message. In this case, the linker could not find the definition of doubleValue
that was called in main
. The declaration in main.cpp
promised that somewhere else there would be a definition for that function. The linkerβs job is to resolve that promise and it canβt because we have not told it to use library.cpp
.
To successfully build the full program that, we need to tell the compiler to build both
library.cpp
and main.cpp
. That way, the linker has all the necessary definitions to work with:
$ g++ main.cpp library.cpp -o program.exe
The code below looks the same, but it is set to compile with the
library.cpp
file from above:
main.cpp
(with declaration) - set to compile with library.cpp and then linkAlthough we can declare the function
doubleValue
in multiple places, we are only allowed to have one definition. This final example illustrates what happens if both main.cpp
and library.cpp
contain a definition for doubleValue
:
main.cpp
(with a second definition)This time, the linker (
ld
) complains about multiple definition of doubleValue(int)
. It found two copies of the function and is not sure which to use. (It will be an error even if the two versions of the function are identical.)
To summarize what we have learned from these examples:
-
Every file is compiled on its own. Any functions used in that file must be declared in that file (but not necessarily defined).
-
The linker merges the compiled files. It must find one (and only one!) copy of every function that is used in the program.
Checkpoint 6.2.2.
Which are the true statements?
- To compile code, all functions used in a file must be declared in that file.
- To compile code, all functions used in a file must be defined in that file.
- To link code, all functions used in the program must be defined in each file.
- To link code, all functions used in the program must be defined in one file.
You have attempted of activities on this page.