Creating several projects from one code in one makefile - c

I have one program and it uses static or shared library. Now I want to do something like
make static
or
make shared
to compile the project in two cases.
My Makefile looks like
shared: main.o libresult.so
gcc -o shared main.o -L. -lresult -Wl,-rpath,.
main.o: main.c
gcc -c main.c
libresult.so: func.o
gcc -shared -o libresult.so func.o
func.o: func.c
gcc -c -fPIC func.c
static: main.o libresult.a
gcc -o static main.o -L. -lresult
main.o: main.c
gcc -c main.c
libresult.a: func.o
ar cr libresult.a func.o
func.o: func.c
gcc -c func.c
clean:
rm -f *.o *.a *.so static shared
Off course, terminal gives some warnings. It works well, but I dont think that
is much beautiful :). How to make it better?

1) You have two copies of the main.o rule:
main.o: main.c
gcc -c main.c
Delete one of them.
2) You have two versions of the func.o rule:
func.o: func.c
gcc -c -fPIC func.c
func.o: func.c
gcc -c func.c
This is a more serious problem. The object you put in the shared library (libresult.so) must be compiled with -fPIC; the object you put in the static library (libresult.a) may be compiled with -fPIC, but there is no reason to do so and it may prevent the compiler form performing some optimisation. Make doesn't know your intentions, so it is better to make two versions of the object with different names:
func_so.o: func.c
gcc -c -fPIC func.c -o func_so.o
func_a.o: func.c
gcc -c func.c -o func_a.o
(Don't forget to modify the rules that rely on these objects.)
3) Use automatic variables to reduce redundancy and make your makefile cleaner. For example:
main.o: main.c
gcc -c $< -o $#
Further improvements are possible, once you are comfortable with these.

Related

Makefile: "undefined reference to cos"

I have just started learning about makefile files. I created a program that consists of two functions and wanted to use a makefile to put it all together. This is my file:
#Makefile
all: main
main: main.o find_root.o
clang -o main main.o find_root.o
main.o: main.c
clang -c -Wall --pedantic -std=c11 main.c -lm
find_root.o: find_root.c
clang -c -Wall --pedantic -std=c11 find_root.c -lm
clean: rm -f main *.o*
However, when I run this, I get an error - "undefined reference to cos". I am using the cosine functions in my program, but I have already linked the library to the compilation of those two files. I thought about adding "-lm" to the first clang option as well. This led to no errors, but it made a warning instead - saying that "-lm linker is unused". What should I change in my file?
The "-lm" is a linker option but you have only included it in your compilation rule (main.o: main.c). You need to include it in your linker rule (main: main.o find_root.o).
As it stand the -lm option is ignored during compilation and missing during linking.
The linker flags aren't used when compiling, but when linking, so the command for the main rule should have -lm, rather than the command for the *.o files.
Better would be just to set the appropriate variables, and let Make use its built-in rules:
#Makefile
LDLIBS += -lm
CFLAGS += -Wall --pedantic -std=c11
C = clang
all: main
main: main.o find_root.o
$(LINK.c) $^ $(LDLIBS) -o $#
clean:
$(RM) main *.o *~

How to compile with a .o file that was compiled with other .o files (C99)

consider c.c a code that includes a.h and b.h, and main.c a code that includes c.h
i tried to compile it like so
gcc --std=c99 -o a.o -c a.c
gcc --std=c99 -o b.o -c b.c
gcc --std=c99 -o c.o -c c.c a.o b.o
but when I run the last one, gcc yells at me
gcc --std=c99 -o c.o -c c.c a.o b.o
gcc: warning: a.o: linker input file unused because linking not done
gcc: warning: b.o: linker input file unused because linking not done
and then when I try to compile the main.c file using gcc -o main main.c c.o it says that there are a lot of undefined references, which is predictable once the c file was not correctly compiled.
I've seen some similar questions here at stackoverflow, but I couldn't get it to work neither way.
I'm on Arch Linux running gcc v4.9.2-3
First, it is -std=c99 with a single dash.
I guess you are on Linux.
Then, you always should pass -Wall -Wextra -g (especially since you are a newbie) to gcc : -Wall ask for nearly all warnings, -Wextra for even more warnings, -g ask for debug information.
At last, you want to produce an executable myprog (don't name executables as c.o, this is supposed to be an object file) with
gcc -std=c99 -Wall -Wextra -g -o myprog c.c a.o b.o
You need to remove any -c since you want the linking to happen.
If you really mean -but that is very unusual today, better make shared libraries!- to agglomerate several object files into one all.o (to be linked later with other objects) you might try the -r linker option
gcc -std=c99 -Wall -Wextra -g -r c.c a.o b.o -o all.o
But last time I tried it was in the previous century, so details could be wrong.
There are very few reasons to agglomerate objects using the -r linker option. Unless you really know what you are doing, you are very probably wrong (in trying -r).
Perhaps you want to make a software library. These days it is much better to make a shared library. A shared library (technically an ELF shared object) should contain position independent code. So, assuming you have three translation units t1.c, t2.c, t3.c you first compile them as PIC :
gcc -std=c99 -Wall -Wextra -g -fPIC t1.c -c -o t1.pic.o
gcc -std=c99 -Wall -Wextra -g -fPIC t2.c -c -o t2.pic.o
gcc -std=c99 -Wall -Wextra -g -fPIC t3.c -c -o t3.pic.o
then you link all these PIC object files into a shared library libmyt.so
gcc -std=c99 -Wall -Wextra -g -shared \
t1.pic.o t2.pic.o t3.pic.o \
-o libmyt.so
Later you'll use this shared library e.g. as
gcc -std=c99 -Wall -Wextra -g main.o -o myprog -Wl,-rpath . libmyt.so
or as
gcc -std=c99 -Wall -Wextra -g main.o -o myprog -Wl,-rpath . -L. -lmyt
You might consider static linking with ar to make a static library libmyt.a but I don't recommend that.
Of course, you'll debug your program using gdb ./myprog and you could try running it with ./myprog. To use valgrind, try valgrind ./myprog
If you have several translation units, better learn how to use GNU make. Read the Program Library HowTo and this and these hints.

MakeFile creation

I want to make a makefile but I am so confused and I need it immediately.
I have four files(.c) an one file(.h). Three of them have main and the fourth hasn't.
main.c has main
readers.c has main
writers.c has main
funs.c has NOT main
The 3 of the files ( that have main ) need the functions in funs.c .
This is my makefile till now:
all: read write main
funs.o:funs.c
gcc -o funs funs.c
read:funs.o
gcc -o read readers.c funs.c
write:funs.o writers.c
gcc -o write writers.c funs.c
main:funs.o main.c
gcc -o main main.c funs.c -lpthread
Can you help? Thanks in advance!
You need to compile funs.o with
gcc -c -o funs funs.c
The -c option makes gcc not try to link the file as a program with main.
There are two steps:
Create a static library for linking
Create each binaries
For example:
all: a b c
STATIC_LIBS=s.o
s.o: share.c
gcc -c -o $# $<
a: a.c $(STATIC_LIBS)
gcc $(STATIC_LIBS) -o $# $<
b: b.c $(STATIC_LIBS)
gcc $(STATIC_LIBS) -o $# $<
c: c.c $(STATIC_LIBS)
gcc $(STATIC_LIBS) -o $# $<
$# is the target
$< is the first dependent object
Well thanks all for your help. This is the answer:
all:read write main
funs.o:funs.c
gcc -c -o funs funs.c
read:readers.c funs.o
gcc -o read readers.c funs.c
write:writers.c funs.o
gcc -o write writers.c funs.c
main:main.c funs.o
gcc -o main main.c funs.c -lpthread

Building a shared library using gcc on Linux and MinGW on Windows

I'm having trouble with generating a build setup that allows shared libraries to be built in both Linux and Windows using gcc and MinGW, respectively. In Linux, a shared library doesn't have to resolve all dependencies at compile time; whereas, this appears to the case in Windows. Here is the problem setup:
$ cat foo.h
#ifndef FOO_H
#define FOO_H
void printme();
#endif
$ cat foo.c
#include "foo.h"
#include <stdio.h>
void printme() {
printf("Hello World!\n");
}
$ cat bar.h
#ifndef BAR_H
#define BAR_H
void printme2();
#endif
$ cat bar.c
#include "bar.h"
#include "foo.h"
void printme2() {
printme();
printme();
}
$ cat main.c
#include "bar.h"
int main(){
printme2();
}
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.so
gcc -shared bar.o -o libbar.so
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
Now, in Linux, this compiles and runs just fine:
$ make
gcc -fPIC -c foo.c
gcc -fPIC -c bar.c
gcc -fPIC -c main.c
gcc -shared foo.o -o libfoo.so
gcc -shared bar.o -o libbar.so
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ ./main
Hello World!
Hello World!
In Windows, we need to change so to dll, which is minor and fine:
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
However, when we try to build, we get the following error:
$ make
gcc -fPIC -c foo.c
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c bar.c
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c main.c
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o -o libbar.dll
bar.o:bar.c:(.text+0x7): undefined reference to `printme'
bar.o:bar.c:(.text+0xc): undefined reference to `printme'
collect2.exe: error: ld returned 1 exit status
make: *** [all] Error 1
Now, we can fix the error by simply including the objects from foo.o into libbar.dll:
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o foo.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ make
gcc -fPIC -c foo.c
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c bar.c
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c main.c
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o foo.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ ./main
Hello World!
Hello World!
However, I don't like this approach since libbar.dll now contains symbols for both foo and bar. In Linux, it only contains symbols for bar. This separation is important for situations where a library depends on some standard numerical library like BLAS. I'd like to be able to deploy the shared library and have it depend on the optimized version of the numerical library on the user's machine and not my own.
In any case, what's the proper procedure to create a shared library where not all of the symbols are present at compile time?
In case it matters, I compiled these examples with gcc 4.6.3 on Linux and mingw-get-inst-20120426.exe with gcc 4.7.2 on Windows.
On Windows, you need to create an import library for the DLL. An import library looks like a static library, in that it defines all of the needed symbols, but it doesn't have the actual function implementations, it just has stubs. The import library will resolve the "undefined reference" errors while avoiding static linking.
To create an import library with MinGW, follow the instructions here. The key is that when building the DLL, you must pass the option -Wl,--out-implib,libexample_dll.a to the linker to generate the import library libexample_dll.a.
Then, when you compile your main executable, you use the -lexample_dll option (along with -L.) to link against the import library. So with your code, I think this should work:
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll -Wl,--out-implib,libfoo.a
gcc -shared bar.o foo.o -o libbar.dll -Wl,--out-implib,libbar.a
gcc main.o -Wl,-rpath=. -L. -lbar -lfoo -o main
Also, note that on Windows, the calling convention for exported functions in DLL is almost always __stdcall, not the default __cdecl, so if you want your DLLs to be usable by other software, I'd recommend making them __cdecl. But that's not strictly requires, as long as both the code in the DLL and the header files agree on what the calling convention is.

function in one shared library calling a function in another shared library

I have a shared library say libfile2.so (which contains print2() function definition). Now I create a libfile1.so (which contains print1() function definition which in turn calls print2() function in libfile2.so). Now I create a main.c file which contains main() function which calls print1() by dynamically linking libfile1.so.
But I am getting the following error:
./libfile1.so: undefined reference to `print2'**
The following are the commands that I am using:
gcc -c -fpic file1.c
gcc -shared -o libfile1.so file1.o
gcc -c -fpic file2.c
gcc -shared -o libfile2.so file2.o
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
gcc -I. -L. -o main main.c -lfile1
If you have called only print1 in your main.c. Then set the path of the libfile2.so in the LD_LIBRARY_PATH. Because it will try to find the dependencies of libfile1.so while linking with main.c.
gcc -o file1.o -c file.c
gcc -o file2.o -c file.c
gcc -o libfile2.so file2.o -shared
gcc -o libfile1.so file1.o -L. -lfile2 -shared
gcc -o main.o -c main.c
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
gcc -o main.exe main.o -L. -lfile1
If you have called both print1 and print2 in main.c then link both libfile1.so and libfile2.so like below.
gcc -o main.o -c main.c
gcc -o main.exe main.o -L$YOUR_LIB_PATH -lfile1 -lfile2
Because all the symbol used in main.c needs to be resolved while generating executable.

Resources