C - programming a makefile and how they work - c

So given three files:
main.h
#include <stdio.h>
void printFunc(*char);
main.c
#include "main.h"
int main(){
printFunc("Hello World\n");
return 0;
}
printFunc.c
#include "main.h"
void printFunc(char *string){
printf("%s", string);
return;
}
You can compile using gcc on a linux machine as follows:
gcc -g -Wall -c file1.c //compile but do not link file
gcc -g -Wall -c file2.c //same
gcc file1.o file2.o -o main //executable "main"
or
gcc -g -Wall file1.c file2.c -o main
But I am concerned with how the header file gets included. I came across this when I was working on creating a "makefile" when I noticed that some tutorials will do something like this:
main : main.o printFunc.o
gcc -o main main.o printFunc.o
main.o : main.c
gcc -g -Wall -c -o main.o main.c
printFunc.o : printFunc.c
gcc -g -Wall -c -o printFunc.o printFunc.c
and others will include the header file as a dependent with:
main : main.o printFunc.o //main.h EDIT
//commands
main.o : printFunc.o main.h
//commands
Finally:
So, is it necessary to include the header file as a dependent to the executable? When does the include file get placed within the sources?
And also one could use this command:
executableName : dependencies.o //and a header file?
gcc -g -Wall -o executableSource.c
Which could be done with the line:
gcc -g -Wall -o executableName executableSource.c
Will the second command be run but the first is shorthand notation?
And finally, I thought the "-o" command was "send output to", if you will. If that way, it seems intuitive to run the command like:
gcc compileThisFile andSendOutputTo thisExecutableFile
gcc someSource.c -o executableFile
But with the notation listed above its more like:
gcc sendOutputTo thisExecutableFile fromThisSource
Is that correct?

main : main.o printFun.o main.h is definitely wrong. That's saying that the header is a prerequisite for linking. A header is a prerequisite for compilation.
Assuming what you really meant was to specify the header as a compilation dependency (e.g. printFunc.o : printFunc.c printFunc.h), this means that if the header changes, the object file will be automatically regenerated. If you don't, then it won't.

A dependency in Makefile is saying that whenever any of the listed files change, run the command again. It does not mean that the listed file will be included into the compilation or linking. You still need the regular #include "main.h" in your sources.
Thus, this works too:
printFunc.o : printFunc.c someReadmeFile.txt
gcc -g -Wall -c -o printFunc.o printFunc.c
Whenever printFunc.c or someReadmeFile.txt is updated, gcc -g -Wall .... will be executed again.
I hope it's clearer now.

Related

How do you link two files in make, that both include a different library?

I want to test my code in test.c which includes main.h with all the function declarations from main.c. I want to compile my test.c file with criterion, which on its own works fine like this: cc -c test.c -o testing -I include -L lib -l criterion.3.1.0 and I compile my main.c in the same way and it works fine: cc main.c -o output -I include -L lib -l SDL2-2.0.0. But when I want to include a function from main.c in test.c it gives me a linking error.
The project architecture is like this:
main.c
#include "main.h"
int function1(){
[...]
}
test.c
#include "main.h"
#include <criterion/criterion.h>
Test(sample,test_function1){
cr_assert(function1() == 1);
}
main.h
#include <SDL2/SDL.h>
extern int function1();
How do I have to compile/link these files in order to have my test-file use get access to the functions from main.c?
What you are currently doing is compiling and linking the binary in a single command for each source file in your project. The linker, with how you are doing this, is not aware of your other sources. Instead, you should first build the object files for each source file, and then you can link those together to form your binary.
Building object files:
cc -c main.c -I include -o main.o
cc -c test.c -I include -o test.o
Linking:
cc -o testing main.o test.o -Llib -lcriterion.3.1.0 -lSDL2-2.0.0

Compilation error on linux server (C project)

I need some help.
I worked on a C project locally and it ran perfect with no issues at all.
Then I moved my whole project files to a linux server (using Bitwise) and ran it using the following command:
gcc -g -std=c99 -Wall -pedantic-errors -Werror -DNDEBUG main.c map.c map.h utilities.c
utilities.h election.c election.h extended_map.c extended_map.h test_utilities.h -o outmap
and again everything worked as expected.
Now, I want to replace my version of test_utilities.h with the version saved on that server, so I opened main.c (which is the only file to include test_utilities.h and replaced:
#include "test_utilities.h"
with
#include "~mtm/public/1920b/ex1/test_utilities.h"
But the terminal shows me the following error:
gcc: error: test_utilities.h: No such file or directory
-bash-4.2$
As suggested I changed it to
gcc -g -std=c99 -Wall -pedantic-errors -Werror -DNDEBUG main.c map.c map.h utilities.c utilities.h election.c election.h extended_map.c extended_map.h test_utilities.h -o outmap -I ~mtm/public/1920b/ex1/
But still I get the following:
gcc: error: test_utilities.h: No such file or directory
update2: (I was requested to remove .h files so now I got)
gcc -g -std=c99 -Wall -pedantic-errors -Werror -DNDEBUG main.c map.c utilities.c election.c extended_map.c -o outmap
Writing ~mtm to refer to the home directory of user mtm is a shortcut that your shell understands. It isn't something that the C preprocessor understands. So you'll have to spell it out as /home/mtm (or wherever mtm's home directory is located) instead of ~mtm.
That said, a better way would be to just leave it as "test_utilities.h" and instead adjust the include path of the compiler (specified via -I when invoking the compiler) to include ~mtm/public/1920b/ex1/.
You also shouldn't specfiy test_utilities.h as an argument to the compiler. In fact none of the header files should be passed as arguments to the compiler.

Where to change LD_LIBRARY_PATH

I want to compile these files into executable.
//main.c
#include <stdio.h>
#include <mylib.h>
int main(void){
call_hello_world();
return 0;
}
//mylib.h
void call_hello_world(void);
//mylib.c
#include <mylib.h>
#include <stdio.h>
void call_hello_world( void ) {
printf( ”Hello world!” );
}
I tried
gcc -c -I. -fPIC -o mylib.o mylib.c
gcc -shared -o libmylib.so mylib.o
gcc -c -o main.o main.c
gcc -o hello main.o -L. -lmylib
but at the third step, I got stucked because it couldn't find my 'mylib.h'. My professor said I needed to change 'LD_LIBRARY_PATH' so I tried to add this export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/dev/shm my .zshrc but it still didn't work for me. Any suggestions what I should do?
There are several issues with your approach.
First, there is a difference between including a header file like this #include <mylib.h> and including it like that #include "mylib.h".
The first option is usually used to include standard library header files, that should be located in the standard set of directories according to the FHS on Linux.
The latter is the option you might want to use as it is usually used to include user-defined headers and tells the preprocessor to search in the directory of the file containing the directive. (See #quest49 answer's https://stackoverflow.com/a/21594/3852949)
The LD_LIBRARY_PATH environment variable is used to indicate where libraries should be searched for first before looking into the standard set of directories.
So what you would want to do to make your main.c file compile, and after changing #include <mylib.h> directive to #include "mylib.h", is to either :
Add the include file into the directory where your main.c file is located
Indicate where the include file path is with -I option to gcc
These are the commands needed :
gcc -c -I. -fPIC -o mylib.o mylib.c
gcc -shared -o libmylib.so mylib.o
gcc -c -I. -o main.o main.c
gcc -o hello main.o libmylib.so
Then in your shell:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/full/path/of/directory/containing/libmylib-so

How to include an archive file in your c code

I'm making an archive file, which I am then trying to include in my code, but when I try to #include 'libutils.h', I get an error:
src/indexer.h:8:10: fatal error: 'libutils.h' file not found
#include "libutils.h"
my make command is:
gcc -g -std=c11 -Wall -pedantic -o indexer src/indexer.c -L. -lutils.a
my file structure is:
Indexer/
libsutil.a obj/ src/ makefile
obj/
web.o list.o hashtable.o //These are the files in the archive file
src/
web.c web.h list.c list.h hashtable.c hashtable.h indexer.c indexer.h
You don't need to include anything, remove the
#include "libutils.h"
from the .c file, and your compilation command will be
gcc -g -std=c11 -Wall -pedantic -o indexer src/indexer.c -L. -lutils

Problems when linking shared library

Below are the steps of how I generate the executable file using shared library.
I have three files:
File libhello.c
/* hello.c - demonstrate library use. */
#include <stdio.h>
void hello(void)
{
printf("Hello, library world./n");
}
File libhello.h
/* hello.h - demonstrate library use. */
void hello(void);
File main.c
/* main.c -- demonstrate direct use of the "hello" routine */
#include "hello.h"
int main(void)
{
hello();
return 0;
}
I use the commands below to generate the shared library.
gcc -g -Wall -fPIC -c hello.c -o hello.o
gcc -shared -W,soname,-libhello.so.0 -o libhello.so.0.0.0 hello.o
Finally, I add the library path to the LD_LIBRARY_PATH variable and try to create the executable file using the shared library.
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
ln -s libhello.so.0.0.0 libhello.so.0
gcc -g -Wall -c main.c -o main.o -I.
gcc -o main main.o -lhello -L.
However, at the last step, there is one error: can't find -lhello. So, where am I wrong?
Thanks.
gcc looks for libhello.so when linking a new program. libhello.so.0 is used when the dynamic dependencies of an already linked program are searched.
In other terms: gcc -o main main.o -lhello -L. looks for libhello.so, and ./main looks for libhello.so.0. This allows to have multiple versions of a library available for legacy programs while precisely identifying the library that matches the installed headers.
A symlink libhello.so -> libhello.so.0.0.0 should do the trick.

Resources