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 includes:

#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

Popular posts from this blog

android - InAppBilling registering BroadcastReceiver in AndroidManifest -

python Tkinter Capturing keyboard events save as one single string -

sql server - Why does Linq-to-SQL add unnecessary COUNT()? -