linker - Why does the compiler only generate object files .o only from .cpp files -
as title says : why compiler generate object files .o .cpp files not header files ? , how linker knows how link object files if implementation in .h files ?
why compiler generate object files .o .cpp files not header files
for concreteness, i'll assume compiler gcc's c++ compiler.
the compiler compile header file object file, if make clear that's want.
header.h
#ifndef header_h #define header_h #include <iostream> inline void hw() { std::cout << "hello world" << std::endl; } #endif
if do:
$ g++ header.h
then won't generate object file, because assumes .h
extension don't want to. instead, generate precompiled header file, header.h.gch
.
this reasonable assumption because don't want compile header file directly object file. usually, don't want compile header file directly @ all, , if do, want pre-compiled header file.
but if want header.h
compiled header.o
, can insist on this:
$ g++ -c -x c++ header.h
which says: compile, without linking, header.h
, treating c++ source file. , output header.o
.
this header.o
pretty useless, however. not, instance, export solitary function hw
linker, because function inlined. if @ symbols in object file:
$ objdump -c -t header.o header.o: file format elf64-x86-64 symbol table: 0000000000000000 l df *abs* 0000000000000000 header.h 0000000000000000 l d .text 0000000000000000 .text 0000000000000000 l d .data 0000000000000000 .data 0000000000000000 l d .bss 0000000000000000 .bss 0000000000000000 l o .bss 0000000000000001 std::__ioinit 0000000000000000 l f .text 000000000000003e __static_initialization_and_destruction_0(int, int) 000000000000003e l f .text 0000000000000015 _global__sub_i_header.h 0000000000000000 l d .init_array 0000000000000000 .init_array 0000000000000000 l d .note.gnu-stack 0000000000000000 .note.gnu-stack 0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 0000000000000000 l d .comment 0000000000000000 .comment 0000000000000000 *und* 0000000000000000 std::ios_base::init::init() 0000000000000000 *und* 0000000000000000 .hidden __dso_handle 0000000000000000 *und* 0000000000000000 std::ios_base::init::~init() 0000000000000000 *und* 0000000000000000 __cxa_atexit
we see there's nothing there boilerplate , things pulled in #include <iostream>
.
we could make header.h
serviceable linkage deleting keyword inline
. if recompile before , have look:
$ objdump -c -t header.o | grep hw 0000000000000061 l f .text 0000000000000015 _global__sub_i__z2hwv 0000000000000000 g f .text 0000000000000023 hw()
we've exported hw()
! can link header.o
in program!
main.cpp
extern void hw(); int main() { hw(); return 0; }
compile that:
$ g++ -c main.cpp
link:
$ g++ -o prog main.o header.o
run:
$ ./prog hello world
but there's snag. we've defined hw()
in header.h
linker can see it, we can't use header.h
in way header files used more, i.e. can't #include "header.h"
in more 1 .cpp
file compiled , linked in same program:
main1.cpp
extern void foo(); extern void bar(); int main() { foo(); bar(); return 0; }
foo.cpp
#include "header.h" void foo(){ hw(); };
bar.cpp
#include "header.h" void bar(){ hw(); };
compile them all:
$ g++ -c main1.cpp foo.cpp bar.cpp
all good. link:
% g++ -o prog main1.o foo.o bar.o bar.o: in function `hw()': bar.cpp:(.text+0x0): multiple definition of `hw()' foo.o:foo.cpp:(.text+0x0): first defined here collect2: error: ld returned 1 exit status
no good, because hw()
defined twice, once in foo.o
, again in bar.o
, , that's linkage error: linker can't pick 1 definition rather other.
so see compiler willing , able compile .h
file c++ source file if insist; it's able , willing compile .blahblah
file c++ source if insist, assumimg there legal c++ in .blahblah
file. header file compiled object file of little or no use us.
the distinction between .h
file , .cpp
file conventional distinction how intend file used. if give .h
extension saying: all c++ in file can safely included in multiple translation units (.cpp
files) compiled , linked together. if give .cpp
extension saying: at least of c++ in file can compiled , linked once in same linkage.
the header.h
started was proper header file, according convention. header.h
deleted inline
no longer header file according convention. should have renamed .cpp
, if don't confusing people.
how linker knows how link object files if implementation in .h files
the linker links nothing object files , libraries. doesn't know .cpp
files or .h
files: might not exist far linker concerned. there 3 ways "implementation" in header file can linker.
1) unconventional way discussed: compiling header file object file, linked. you've seen, there no technical problem in doing that, though in practice it's never done.
2) usual way, #include
-ing header file in .cpp
file.
hello.h
#ifndef hello_h #define hello_h static char const * hw = "hello world"; #endif
hello.cpp
#include "hello.h" char const * hello = hw;
in case, compiler preprocesses hello.cpp
before starts generate object code, , can see compiler sees after preprocessor finished telling compiler preprocessing , nothing else:
$ g++ -p -e hello.cpp static char const * hw = "hello world"; char const * hello = hw;
the output of command translation unit compiled hello.o
, , see, code in hello.h
copied translation unit in place of #include "hello.h"
.
so time compiler starts generate hello.o
, header hello.h
irrelevant: might not exist.
3) compiling header.h
file pre-compiled header.h.gch
. header.h.gch
"semi-compiled" form of header.h
#include
-ed, if exists, whenever #include "header.h"
or #include <header.h>
appears in code. difference semi-compiled header.h.gch
can processed faster header.h
: (3) faster version of (2) (and has limitation compiler accept 1 precompiled header per compilation.)
whether gets there (1),(2) or (3), linkage of code .h
file no different linkage of code .cpp
file. code compiled compiler. compiler doesn't care whether code originates in .h
file or .cpp
file. compiler generates object files, , linker links object files.
Comments
Post a Comment