compilation - Proper way to include C code from directories other than the current directory -
i have 2 directories, sorting
, searching
(children of same directory), have .c
source files , .h
header files:
mbp:c $ ls sorting array_tools.c bubble_sort.c insertion_sort.c main selection_sort.c array_tools.h bubble_sort.h insertion_sort.h main.c selection_sort.h mbp:c $ ls searching array_tools.c array_tools.h binary_search.c binary_search.h linear_search.c linear_search.h main main.c
within searching
, building executable needs use insertion_sort
function, declared in insertion_sort.h
, defined in insertion_sort.c
inside sorting
. following compilation produces executable:
mbp:searching $ clang -wall -pedantic -g -iquote"../sorting" -o main main.c array_tools.c binary_search.c linear_search.c ../sorting/insertion_sort.c
however, able include functions arbitrary directories including header using #include
, providing compiler search path. need precompile .c
files .o
files beforehand? man
page clang lists following option:
-i<directory> add specified directory search path include files.
but following compilation fails:
mbp:searching $ clang -wall -pedantic -g -i../sorting -o main main.c array_tools.c binary_search.c linear_search.c undefined symbols architecture x86_64: "_insertion_sort", referenced from: _main in main-1a1af0.o ld: symbol(s) not found architecture x86_64 clang: error: linker command failed exit code 1 (use -v see invocation)
main.c
has following include
s:
#include <stdio.h> #include <stdlib.h> #include "linear_search.h" #include "binary_search.h" #include "array_tools.h" #include "insertion_sort.h"
i not understand link between header files, source files, , object files. include function defined in .c
file, sufficient include homonymous header file, given .c
file in same directory header? have read multiple answers here on so, man
page clang , number of tutorials, unable find definitive, clear answer.
in response @spectras:
one one, give compiler source file work on. instance:
cc -wall -ipath/to/some/headers foo.c -o foo.o
running
mbp:sorting $ clang -wall insertion_sort.c -o insertion_sort.o
produces following error:
undefined symbols architecture x86_64: "_main", referenced from: implicit entry/start main executable ld: symbol(s) not found architecture x86_64 clang: error: linker command failed exit code 1 (use -v see invocation)
okay, it's mixed bit. let's see how 1 typically compiles simple multi-file project.
one one, give compiler source file work on. instance:
cc -c -wall -ipath/to/some/headers foo.c -o foo.o
the -c
flag tells compiler want object file, should not run linker.
the compiler runs preprocessor on source file. among other things, every time sees
#include
directive, searches include paths named file , copy-pastes it, replacing#include
content. done recursively.this step
.h
include merged source file. call whole thing translation unit.you can see result of step using
-e
flag , inspect result, instance:cc -wall -ipath/to/some/headers foo.c -e -o foo.test
let's make short other steps not relevant question. compiler creates object file resulting source code. object file contains binary version of code , data in translation unit, plus metadata used put , other stuff (like debugging info).
you can inspect contents of object file using
objdump -xd foo.o
.
note done each source file, means headers parsed , compiled again , again , again. that's reason should declare stuff , not contain actual code: end code in every object file.
once done, link object files executable, instance:
cc foo.o bar.o baz.o -o myprogram
this step gather all, resolve dependencies , write executable binary. may pull in external object files using -l
, when -lrt
or -lm
.
for instance:
- foo.c includes bar.h
- bar.h contains declaration of function do_bar:
void do_bar(int);
- foo.c can use it, , compiler generate foo.o correctly
- foo.o have placeholders , information requires
do_bar
- bar.c defines implementation of
do_bar
. - so bar.o have information “hey if needs
do_bar
, got here”. - linking step replace placeholders actual calls
do_bar
.
finally, when pass multiple .c
files compiled in question, compiler same thing, won't generate intermediate object files. overall process behaves same though.
so, error?
undefined symbols architecture x86_64: "_insertion_sort", referenced from: _main in main-1a1af0.o ld: symbol(s) not found architecture x86_64 clang: error: linker command failed exit code 1 (use -v see invocation)
see? says linking step failed. means previous step went well. #include
worked. it's in linking step, it's looking symbol (data or code) called _insertion_sort
, , not find it. that's because symbol declared somewhere (otherwise source using not have compiled), definition not available. either no source file implemented it, or object file contains not given linker.
=> need make _insertion_sort
's definition available. either adding ../sorting/insertion_sort.c
source lists pass or compiling object file , passing that. or building library can shared 2 binaries (otherwise they'll each have copy embedded).
when there, starting use build toolsuite such cmake
idea. take care of details you.
Comments
Post a Comment