Shared library from archive (.a) file in C - c

I was given a task to create archive file .a from objects file and create a shared library file from archive .a file. I have tried experiment having following file:
foo.h
#ifndef _foo_h__
#define _foo_h__
extern void foo(void);
extern void bar(void);
#endif //_foo_h__
foo.c
#include<stdio.h>
void foo(void)
{
puts("Hello, I'm a shared library");
}
bar.c
#include<stdio.h>
void bar(void)
{
puts("This is bar function call.");
}
main.c
#include <stdio.h>
#include"foo.h"
int main(void)
{
puts("This is a shared library test...");
foo();
bar();
return 0;
}
Makefile
CFLAGS = -Wall -Werror
LDFLAGS = -L/home/betatest/Public/implicit-rule-archive -Wl,-rpath,'$$ORIGIN'
all : run
run : main.o libfoo.so
$(CC) $(LDFLAGS) -o $# $^
libfoo.so : CFLAGS += -fPIC # Build objects for .so with -fPIC.
libfoo.so : libfoo.a
$(CC) -shared -o $# $^
libfoo.a : foo.o bar.o
ar cvq libfoo.a foo.o bar.o
# ar cr libfoo.a foo.o bar.o
# Compile any .o from .c. Also make dependencies automatically.
%.o : %.c
$(CC) -c $(CFLAGS) -o $# $<
#Include dependencies on subsequent builds.
.PHONY : all clean
clean :
-rm -f *.o *.d run libfoo.*
This simple test program seems to run fine but while compiling using make it producing error as:
cc -c -Wall -Werror -o main.o main.c
cc -c -Wall -Werror -fPIC -o foo.o foo.c
cc -c -Wall -Werror -fPIC -o bar.o bar.c
ar cvq libfoo.a foo.o bar.o
a - foo.o
a - bar.o
cc -shared -o libfoo.so libfoo.a
cc -L/home/betatest/Public/implicit-rule-archive -Wl,-rpath,'$ORIGIN' -o run main.o libfoo.so
main.o: In function `main':
main.c:(.text+0xf): undefined reference to `foo'
main.c:(.text+0x14): undefined reference to `bar'
collect2: ld returned 1 exit status
Makefile-test:7: recipe for target 'run' failed
make: *** [run] Error 1
Somebody please point out that where I am getting wrong?? Thanks a lot.

If you wish to build a shared library from a static library you have to tell the linker to use all function/symbols included in static library (.a). Otherwise nothing will be included in the shared library (.so).
You have to use --whole-archive/--no-whole-archive pair in linking.
CFLAGS = -Wall -Werror
LDFLAGS = -L/home/betatest/Public/implicit-rule-archive -Wl,-rpath,'$$ORIGIN'
all : run
run : main.o libfoo.so
$(CC) $(LDFLAGS) -o $# $^
libfoo.so : CFLAGS += -fPIC # Build objects for .so with -fPIC.
libfoo.so : libfoo.a
$(CC) -shared -o $# -Wl,--whole-archive $^ -Wl,--no-whole-archive
libfoo.a : foo.o bar.o
ar cvq libfoo.a foo.o bar.o
# Compile any .o from .c. Also make dependencies automatically.
%.o : %.c
$(CC) -c $(CFLAGS) -o $# $<
#Include dependencies on subsequent builds.
.PHONY : all clean
clean :
-rm -f *.o *.d run libfoo.*
You can check the exported functions using nm command:
$ nm -D libfoo.so | grep ' T '
0000000000000702 T bar
0000000000000714 T _fini
00000000000006f0 T foo
0000000000000590 T _init
When no --whole-archive/--no-whole-archive pair is used you get:
$ nm -D libfoo.so | grep ' T '
0000000000000714 T _fini
0000000000000590 T _init

Your mistake is in the question: do not make shared library from archive, make it from objects, i.e. change Makefile like this
libfoo.so : foo.o bar.o
$(CC) -shared -o $# foo.o bar.o
you can also use %.o to mean all objects
also you need CFLAGS = -fPIC globally, to affect compilation command, not only the link step, that is you .o object files should be position-independent.
also here extern is not needed, all C functions are implicitly extern
extern void foo(void);
I would also not recommend using rpath and better
export LD_LIBRARY_PATH=.
to load .so from current directory (or export path to .so's directory)

Related

Makefile: Trying to understand sequence of execution

I have the following Makefile.
objects = foo.o bar.o all.o -- line 1
all: $(objects)
# These files compile via implicit rules
foo.o: foo.c
bar.o: bar.c
all.o: all.c
all.c:
echo "int main() { return 0; }" > all.c
%.c:
touch $#
clean:
rm -f *.c *.o all
When i run make, i get the below output.
echo "int main() { return 0; }" > all.c
cc -c -o all.o all.c
touch foo.c
cc -c -o foo.o foo.c
touch bar.c
cc -c -o bar.o bar.c
cc all.o foo.o bar.o -o all
Question:
Line 1 of the Makefile shows foo.o is the first dependency. So why all.o which depends on all.c are executed first?
You are confusing things by having the file all.c (and object file all.o) and the target all. Conventionally, the all target is a pseudo-target (.PHONY in GNU Make) for 'all the things that are (normally) built by this makefile. This isn't enforced — it is merely convention.
However, here, make is trying to use all.c to build a program all. And it knows it can build all by compiling all.c, so it generates that first.
You could clarify things by either using any.c instead of all.c and building any.o and program any, and having the all: target read:
all: any
That would build the program any

I have been working on this makefile for hours. It keep getting the error: make: *** No rule to make target 'hangman.c', needed by 'hangman.o'. Stop

CFLAGS=-std=c99 -Wall
CC=gcc
hangman: hangman.o hangman.c
$(CC) $(CFLAGS) hangman.o hangman.c -o hangman
hangman.o: hangman.c
$(CC) $(CFLAGS) -c hangman.c
clean:
rm -f hangman *.o
Well, hangman (the program binary) only depends of hangman.o, but not of hangman.c, which has already been compiled into hangman.o (at compilation phase).
In Makefile, you only state the direct dependencies, while make(1) does the rest of the work.
I use to designate all the objects to a program in a variable, as they will be used several times. In this way:
# Makefile -- make file for hangman.
targets = hangman
hangman_objs = hangman.o
hangman: $(hangman_objs)
$(CC) $(LDFLAGS) -o hangman $(hangman_objs)
and nothing else, as make(1) has an automatic rule, that is
.c.o:
$(CC) $(CFLAGS) -o $# -c $<
which is the equivalent to this rule:
hangman.o: hangman.c
$(CC) $(CFLAGS) -o hangman.o -c hangman.c
(and the same for each .c and .o file you can have.)
By the way, the error you are receiving, is that make has found a dependency on hangman.c but doesn't find any file called hangman.c so it needs to build it, but you don't provide this file. You have probably erased your hangman.c file (which is something that sometimes happen if you mispell files in the Makefile, make ends erasing files that are important for you) In this case, it tries to build handman which depends on handman.o which depends on handman.c, so no finding handman.c makes make(1) to say, I have a dependency on handman.c but no such file is found (and I have no dependency to follow that allows me to build it)
If your project is a single source project, then you can avoid the generation of hangman.o and create a Makefile like this:
hangman: hangman.c
$(CC) $(CFLAGS) $(LDFLAGS) -o hangman hangman.c
Which states an explicit, direct reference from the binary to the source code. In this case, you don't use the -c flag to the compiler to just compile, and don't link, and build your executable directly with one command. This is not used in large projects, as normally you want to just compile the sources that have changed. As in this example:
hangman_objs = hang.o man.o foo.o bar.o a.o b.o c.o
hangman: $(hangman_objs)
$(CC) $(LDFLAGS) -o hangman $(hangman_objs)
if you expand the variable, you'll get this rule:
hangman: hang.o man.o foo.o bar.o a.o b.o c.o
cc -o hangman hang.o man.o foo.o bar.o a.o b.o c.o
#all this are automatic dependencies generated from
# .c.o:
# $(CC) $(CFLAGS) -c $< -o $#
# for the files hang.o man.o foo.o bar.o a.o b.o c.o
hang.o: hang.c
cc -O2 -pipe -c hang.c -o hang.o
man.o: man.c
cc -O2 -pipe -c man.c -o man.o
foo.o: foo.c
cc -O2 -pipe -c foo.c -o foo.o
bar.o: bar.c
cc -O2 -pipe -c bar.c -o bar.o
a.o: a.c
cc -O2 -pipe -c a.c -o a.o
b.o: b.c
cc -O2 -pipe -c b.c -o b.o
c.c: c.c
cc -O2 -pipe -c c.c -o c.o
but you must not use both, the object code and the source code in the linking phase of your program. The compiler will link the file you provide hangman.o and will compile it also (which generates a new hangman.o) and will try to link both (two versions of the same code) and that can generate new errors.
My approach to your program would be:
# main targets to build (programs)
targets = hangman
# toclean maintains everything must be erased on clean.
toclean = $(targets)
# object files of hangman target
hangman_objs = hangman.o foo.o
# add all those objects to the toclean variable.
toclean += $(hangman_objs)
# libraries
hangman_ldflags = -L path/to/libbar
hangman_libs = -lbar
# main target all
all: $(targets)
# ... and clean
clean:
rm -f $(toclean)
# just the link phase, the compiling is automatically done.
hangman: $(hangman_objs)
$(CC) $(LDFLAGS) $($#_ldflags) -o $# $($#_objs) $($#_libs)

Dynamic library with multiple object files, fails during loading

Similar to this post: Compile multiple C source fles into a unique object file
I have to compile multiple C files into a single dynamic shared library.
Here is what I have in my Makefile:
_OBJS = file1.o file2.o
CFLAGS += -Wall -I../include
SHARED_LIB =libdynamic.so
.PHONY: all
all: (SHARED_LIB)
$(SHARED_LIB):
$(CC) -fPIC -c file1.c file2.c $(CFLAGS)
$(CC) -shared -o $(SHARED_LIB) -L$/lib -ldl $(_OBJS)
However the generated shared library doesn't have the functions belonging to file2.c. How can I get it working?
Thanks.
You're not creating the object files (*.o).
Try:
$(SHARED_LIB):
$(CC) -fPIC -c file1.c -o file1.o $(CFLAGS)
$(CC) -fPIC -c file2.c -o file2.o $(CFLAGS)
$(CC) -shared -o $(SHARED_LIB) -L$/lib -ldl $(_OBJS)
Also, you are missing a '$' after the all: target.

GCC Linking with .o file

I'm trying to compile my code but it isn't working. I got this to compile at school but I can't compile this on my home computer. I can't seem to figure out why. I need this error fixed in order to continue my assignment. Also, this list.o file is the profs file. I have to use this file.
Solutions I've tried kind of?
I've updated gcc to gcc-7.
I've located libc.a
/usr/lib/x86_64-linux-gnu/libc.a
/usr/share/doc/libklibc/README.klibc.arch
Edit: I have tried compiling without -fPIC
gcc -m64 -pthread -Wall -std=c99 -o run main.o as2.o list.o
/usr/bin/ld: list.o: relocation R_X86_64_32S against undefined symbol...
This is from the terminal:
gcc -m64 -pthread -Wall -std=c99 -fPIC -o run main.o as2.o list.o
/usr/bin/ld: list.o: relocation R_X86_64_32S against undefined symbol `headlist' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
This is my make file:
CC = gcc
CFLAGS = -m64 -pthread -Wall -std=c99 -fPIC
PROG = run
OBJS = main.o as2.o list.o
run: $(OBJS)
$(CC) $(CFLAGS) -o $(PROG) $(OBJS)
main.o: main.c list.h as2.h
$(CC) $(CFLAGS) -c main.c
as2.o: as2.c as2.h list.h
$(CC) $(CFLAGS) -c as2.c
clean:
rm main.o as2.o run
This is my includes:
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "list.h"
#include "as2.h"
Any ideas/solutions?
EDIT:
changed the spelling from LFLAGS to LDFLAGS to appease some comment.
EDIT:
moved the -c option to appease some comment.
Note: all is normally the first target in a make file.
Note: used := rather than = so the macros would only be evaluated once.
Note: the list.o is already available in the current directory (per the OPs question) so is not compiled in the makefile. But is only linked with the other object files to produce the executable
your makefile seems to have a few oversights. Suggest:
CC := gcc
RM := rm -f
CFLAGS := -ggdb -m64 -pthread -Wall -Wextra -pedantic -std=c99
#LDFLAGS := <-- use the default value
PROG := run
OBJS := main.o as2.o list.o
HDRS := list.h as2.h
.PSEUDO: all clean
all: $(PROG)
$(PROG): $(OBJS)
$(CC) -ggdb -o $(PROG) $(OBJS) $(LDFLAGS)
main.o: main.c $(HDRS)
$(CC) $(CFLAGS) -c main.c -o main.o -I.
as2.o: as2.c $(HDRS)
$(CC) $(CFLAGS) -c as2.c -o as2.o -I.
clean:
$(RM) main.o as2.o run

makefile for creating (.so) file from existing files

I have 4 files: 1.c, 1.h, 2.c, 2.h.
I need a makefile, which will create a dynamic library (.so) from those 4 files.
I have tried to write a makefile like this:
library.so : 1.c 1.h 2.c 2.h
but it did not work. It would be great, if someone helps me, thanks.
Something like
CC=gcc
CFLAGS= -Wall -g -O -fPIC
RM= rm -f
.PHONY: all clean
all: library.so
clean:
$(RM) *.o *.so
library.so: 1.o 2.o
$(LINK.c) -shared $^ -o $#
1.o: 1.c 1.h 2.h
2.o: 2.c 1.h 2.h
But this is untested! I am assuming Linux with GNU make, and a directory containing only the source code of your library (with the above Makefile), which might be bad practice -you might want a test case- (you could have a special Makefile rule for %.pic.o depending on %.c, etc...)
Hints: use make -p to understand the builtin rules. Then make --trace or (with remake) remake -x to understand a bit more what make is doing.
Read also Drepper's paper: How to Write Shared Libraries, documentation of GNU make, Program Library HowTo, this answer, ...
The simplest way is:
CXXFLAGS += -fPIC
CXXFLAGS += -O3
x.so: 1.o 2.o
$(LINK.cc) -shared $^ $(LOADLIBS) $(LDLIBS) -o $#
Slightly more advanced:
CC = gcc
FLAGS = # -std=gnu99 -Iinclude
CFLAGS = -fPIC -g #-pedantic -Wall -Wextra -ggdb3
LDFLAGS = -shared
DEBUGFLAGS = -O0 -D _DEBUG
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
TARGET = example.so
SOURCES = $(wildcard *.c)
HEADERS = $(wildcard *.h)
OBJECTS = $(SOURCES:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(FLAGS) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) $(OBJECTS)
CC = gcc # C compiler
CFLAGS = -fPIC -Wall -Wextra -g # C flags
LDFLAGS = -shared # linking flags
RM = rm -f # rm command
TARGET_LIB = sh_main.so # target lib
SRCS = add.c sub.c main.c # source file
DEPS = header.h # header file
OBJS = $(SRCS:.c=.o) # object file
.PHONY: all
all: ${TARGET_LIB}
$(TARGET_LIB): $(OBJS)
$(CC) ${LDFLAGS} -o $# $^ # -o $# says, put the output of the compilation in the file named on the left side of the :
$(SRCS:.c=.d):%.d:%.c
$(CC) $(CFLAGS) -MM $< >$# # the $< is the first item in the dependencies list, and the CFLAGS macro is defined as above
include $(SRCS:.c=.d)
.PHONY: clean
clean:
-${RM} ${TARGET_LIB} ${OBJS} $(SRCS:.c=.d)
After the shared library created successfully. We need to install it.
Become the root user.
Copy the shared library into standard directory "/usr/lib".
Run ldcofig command.
Recompile your .c file with shared library.
root#Admin:~/C/SharedLibrary# gcc -c main.c
root#Admin:~/C/SharedLibrary# gcc -o main main.o sh_main.so
root#Admin:~/C/SharedLibrary# ldd main
Note: In my case.
main.c: main C file
sh_main.so: shared library.
I'm no gnu make expert, this seems reasonable to me
CFLAGS+=-fPIC
%.so: ; $(LINK.c) $(LDFLAGS) -shared $^ -o $#
library.so: 1.o 2.o # default target first
# changes to `1.h` imply `1.o` needs to be rebuilt
1.o: 1.h
2.o: 2.h

Resources