Dynamic library with multiple object files, fails during loading - c

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.

Related

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)

Undefined reference and linking libraries

I'm experiencing some compilation issues with my dynamic library. It should be linked to main.c but for all references to it I receive "undefined reference to function_name".
The contents of main.c isn't really that important; I include my library:
#include "matrix.h"
Then I have a simple Makefile to link the two.
#Variables
LIB = matrix
# Usual compilation flags
CFLAGS = -std=c99 -Wall -Wextra -g
CPPFLAGS = -I../include -DDEBUG
LDFLAGS = -lm
# Special rules and targets
.PHONY: all clean help
all: $(LIB).o libmatrix.so main
$(LIB).o: $(LIB).c $(LIB).h
$(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -c -o $# $<
libmatrix.so: $(LIB).o
$(CC) $(CFLAGS) -fPIC -shared -o $# $< $(LDFLAGS)
main: main.o libmatrix.so
$(CC) $(CFLAGS) -o $# $< -L -lmatrix
Can anyone direct me to where I might be going wrong? Many thanks in advance.
You probably want -L. not -L in your last line, so:
main: main.o libmatrix.so
$(CC) $(CFLAGS) -o $# $< -L. -lmatrix
You should read Program Library HOWTO and Drepper's paper: How to Write Shared Libraries; you might want to set some -rpath at link time (maybe using -Wl,-rpath,. ...), and you might want to link with -rdynamic ....
Alternatively, set your LD_LIBRARY_PATH environment variable to contain . (I don't recommend that), or install your shared library in /usr/local/lib/ (and add it to /etc/ld.so.conf then run ldconfig). See also dlopen(3), environ(7), ld.so(8), ldconfig(8)

makefile compiling multiples targets

This is my first post in this forum. Sorry for bothering but I've been looking for something similar and strangely I couldn't find it. Here's the issue.
I have three (main) files with no headers and I want to compile them either at once (if I simply type "make") or one by one (if I specify the name of the file with no extension). So I built my makefile but something is wrong in the command
$(TARGETS): $(BUILDS_DIR)% : $(SRCS_DIR)%.c
where I got this error
make: *** No rule to make target....
here's the complete file
.SUFFIXES: .c
ROOT = $(addprefix $(PWD), /)
BUILDS_DIR = $(addprefix $(ROOT), builds/)
SRCS_DIR = $(addprefix $(ROOT), src/)
SRCS = $(wildcard $(SRCS_DIR)*.c)
TARGETS = ${SRCS:$(SRCS_DIR)%.c=%}
EXES = ${addprefix $(BUILDS_DIR), $(TARGETS)}
CC = gcc
CFLAGS = -Wall -O3
RM = rm -f
.PHONY: all $(TARGETS) clean
all: $(TARGETS)
$(TARGETS): $(BUILDS_DIR)% : $(SRCS_DIR)%.c
$(CC) $(CFLAGS) \
$< \
-o $#
#echo -e "\n\n\t\t*** Compile successfully! ***\n" ;
clean:
$(RM) $(EXES) \
$(SRCS_DIR)*~
#echo -e "\n\n\t\t*** Cleanup complete! ***\n"
Where am I wrong? I guess the answer is very silly and probably based on a basic error.
thanks in advance
Assuming GNU Make (since you use its syntax).
The, or the first, problem is that you are trying to rewrite the target static pattern incorrectly, by trying to concatenate the target directory to the pattern, rather than simply using the target's filename.
You had:
$(TARGETS): $(BUILDS_DIR)% : $(SRCS_DIR)%.c
$(CC) $(CFLAGS) $< -o $#
The solution is to use add the directory path on the command line
$(TARGETS): % : $(SRCS_DIR)%.c
$(CC) $(CFLAGS) $< -o $(BUILDS_DIR)$#
Lets assume that your three source files are file1.c, file2.c and file3.c. I would created the makefile to look like this (assuming GNU make)
CC = gcc
CFLAGS = -ansi -Wall -pedantic
RM = rm -f
OBJS = file1.o file2.o file3.o
PROG=my_program
$(PROG) : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(PROG)
all : clean $(PROG)
file1 : file1.c
$(CC) $(CFLAGS) -c file1.c -o file1.o
file2 : file2.c
$(CC) $(CFLAGS) -c file2.c -o file2.o
file3 : file3.c
$(CC) $(CFLAGS) -c file3.c -o file3.o
clean :
$(RM) *.o $(PROG) *.*~
A sample using this make file is (I use the -n to show what rules would be run, but not actually run them because my source files are empty files for testing.)
[******#broadsword junk]$ make -n
gcc -ansi -Wall -pedantic -c -o file1.o file1.c
gcc -ansi -Wall -pedantic -c -o file2.o file2.c
gcc -ansi -Wall -pedantic -c -o file3.o file3.c
gcc -ansi -Wall -pedantic file1.o file2.o file3.o -o my_program
[******#broadsword junk]$ make -n file1
gcc -ansi -Wall -pedantic -c file1.c -o file1.o
We can shorten the above make file my making use of wild-cards;
CC = gcc
CFLAGS = -ansi -Wall -pedantic
RM = rm -f
OBJS = file1.o file2.o file3.o
PROG=my_program
$(PROG) : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(PROG)
all : clean $(PROG)
% : %.c
$(CC) $(CFLAGS) -c $< -o $#.o
clean :
$(RM) *.o $(PROG) .~
We need to append a '.o' to the output file name so that we are creating files in the format defined by the $(OBJ) variable of the first build rule works correctly. Doing this gives the following example runs:
[******#broadsword junk]$ make -n
gcc -ansi -Wall -pedantic -c -o file1.o file1.c
gcc -ansi -Wall -pedantic -c -o file2.o file2.c
gcc -ansi -Wall -pedantic -c -o file3.o file3.c
gcc -ansi -Wall -pedantic file1.o file2.o file3.o -o my_program
[******#broadsword junk]$ make -n file2
gcc -ansi -Wall -pedantic -c file2.c -o file2.o
BTW, I personally don't mind typing an extra two characters and I like having my target match the output of the set of rules that get run, so I would write the rules as either
file1.o : file1.c
$(CC) $(CFLAGS) -c file1.c -o file1.o
or
%.o :%.c
$(CC) $(CFLAGS) -c $< -o $#
Finally I strongly suspect that when we execute make or make all, we are not running the file-specific rules in the lower part of the makefile, rather we are running the the built in rule described in the GNU manual as: "n.o is made automatically from n.c with a recipe of the form $(CC) $(CPPFLAGS) $(CFLAGS) -c".

"make clean" causes "make all" failure

When I execute this Makefile without clean, it functions OK and both the shared library and the main executable are created correctly. However, when I add the clean target, the "make all" fails. What could be the reason?
CC = gcc
CFLAGS = -fPIC -Wall -Werror
LDFLAGS = -shared
TARGET_LIB= libnsd.so
lib: nsd.o nd.o
$(CC) $(LDFLAGS) -o ${TARGET_LIB} nsd.o nd.o -lm
nd.o : nd.c nd.h
$(CC) -c $(CFLAGS) nd.c
nsd.o : nsd.c nsd.h
$(CC) -c $(CFLAGS) nsd.c
all: main.c
$(CC) -o -I. -L. main.c -lnsd
clean:
rm -f libnsd.so nd.o nsd.o
Your all: target needs to depend on the lib target, so the library is built first.
The -o argument to the compiler also needs a name for executable it should create.
all: lib main.c
$(CC) -o main -I. -L. main.c -lnsd
Normally you want the target name to be the file that you create, otherwise things get rebuilt when it's not needed. (the lib: target has the same issue) but as an exampe for the executable:
.PHONY: all
all: lib main
main: lib main.c
$(CC) -o main -I. -L. main.c -lnsd
nos's answer is on the right track.
It only appeared to work before, because you happened to run make in the right order. It won't work after a clean operation because, as nos points out, you have not declared all of your prerequisites. The rule that links main.o must depend on the shared library target, so make knows the right order to build things.
Also, you REALLY want your targets to be the actual file you're building. If they're something else, then make will always think they're out of date even if you haven't changed anything, and always rebuild them.
Something like this will be better:
CC = gcc
CFLAGS = -fPIC -Wall -Werror
CPPFLAGS = -I.
LDFLAGS = -shared
PROGRAM = main
TARGET_LIB= libnsd.so
all: $(PROGRAM)
$(PROGRAM): main.o $(TARGET_LIB)
$(CC) -o $# -L. main.o -lnsd
$(TARGET_LIB): nsd.o nd.o
$(CC) $(LDFLAGS) -o $# nsd.o nd.o -lm
nd.o : nd.c nd.h
nsd.o : nsd.c nsd.h
clean:
rm -f libnsd.so *.o

What is the proper way to create library files with a Makefile? [C]

I am making my first Makefile for a simple shell system. I need to make library files but for some reason the library section is not working out. In the error message it says the library files do no exist (obviously).
Am I missing something obvious that could fix this? Also, is there any other way I can make this Makefile more efficient?
# Beginning of Makefile
OBJS = obj/shutil.o obj/parser.o obj/sshell.o obj/history.o obj/hash_table.o obj/variables.o
HEADER_FILES = include/shell.h include/parser.h include/history.h include/hash_table.h include/variables.h
EXECUTABLE = sshell
LIBS = lib/libshell.so lib/libparser.so lib/libhistory.so lib/libhash_table.so lib/libvariables.so
LIBCFLAGS = $(CFLAGS) -D_REENTRANT -fPIC
CFLAGS = -Wall
CC = gcc
# End of configuration options
#What needs to be built to make all files and dependencies
all: $(EXECUTABLE)
#Create the main executable
$(EXECUTABLE): $(OBJS) $(LIBS)
$(CC) -o $(EXECUTABLE) obj/sshell.o -Llib -lparser -lshell -lhistory -lhash_table -lvariables
#Create the library files
$(LIBS): $(OBJS)
$(CC) $(LIBCFLAGS) -shared -o $(LIBS) $(OBJS)
#Recursively build object files
obj/%.o: src/%.c
$(CC) $(CFLAGS) -I./include/ -c $< -o $#
#Define dependencies for objects based on header files
#We are overly conservative here, parser.o should depend on parser.h only
$(OBJS) : $(HEADER_FILES)
clean:
-rm -f $(EXECUTABLE) obj/*.o lib/*.so lib/*.a
-rm -f .sshell_history.txt
run: $(EXECUTABLE)
(export LD_LIBRARY_PATH=lib; ./$(EXECUTABLE))
# End of Makefile
Thanks!
-Lily Banks
Edit:
Before I tried to change it, here is what I had with regards to library files.
$(LIBS): $(OBJS)
$(CC) -shared -o lib/libparser.a obj/parser.o
$(CC) -shared -o lib/libshell.a obj/shutil.o
$(CC) -shared -o lib/libhistory.a obj/history.o
$(CC) -shared -o lib/libhash_table.a obj/hash_table.o
$(CC) -shared -o lib/libvariables.a obj/variables.o
The problem with this was that it compiled each file five times which is not efficient at all. So what I was trying to do was do it all in one go.
Edit2:
#Create the library files
lib/libparser.so: obj/parser.o
$(CC) $(LIBFLAGS) -shared lib/libparser.a -o $#
lib/libshell.so: obj/shutil.o
$(CC) $(LIBFLAGS) -shared lib/libshell.a -o $#
lib/libhistory.so: obj/history.o
$(CC) $(LIBFLAGS) -shared lib/libhistory.a -o $#
lib/libhash_table.so: obj/hash_table.o
$(CC) $(LIBFLAGS) -shared lib/libhash_table.a -o $#
lib/variables.so: obj/variables.o
$(CC) $(LIBFLAGS) -shared lib/libvariables.a -o $#
Unfortunately, here is the error I am getting:
make: *** No rule to make target `lib/libvariables.so', needed by `sshell'. Stop.
Thoughts?
Edit3:
#Create the library files
lib/libparser.so: obj/parser.o
$(CC) $(LIBFLAGS) -shared $^ -o lib/libparser.a
lib/libshell.so: obj/shutil.o
$(CC) $(LIBFLAGS) -shared $^ -o lib/libshell.a
lib/libhistory.so: obj/history.o
$(CC) $(LIBFLAGS) -shared $^ -o lib/libhistory.a
lib/libhash_table.so: obj/hash_table.o
$(CC) $(LIBFLAGS) -shared $^ -o lib/libhash_table.a
lib/libvariables.so: obj/variables.o
$(CC) $(LIBFLAGS) -shared $^ -o lib/libvariables.a
This works but is there anything else I need to change? Thanks
You need one set of object files for each library. And the -o flag only takes one argument which is the output file, you are trying to output all the library files which you cannot do with one invocation of gcc.
You need to do something like:
lib/libshell.so: obj/sshell.o
$(CC) $(LIBFLAGS) -shared obj/sshell.o -o lib/libshell.so
lib/libparser.so: obj/parser.o
$(CC) $(LIBFLAGS) -shared obj/parser.o -o lib/libparser.so
for each of the libraries.
This line is completely wrong:
$(LIBS): $(OBJS)
$(CC) $(LIBCFLAGS) -shared -o $(LIBS) $(OBJS)
If you expanded all the variables, this line would look like this (adding line breaks for clarity):
lib/libshell.so lib/libparser.so lib/libhistory.so lib/libhash_table.so lib/libvariables.so: \
obj/shutil.o obj/parser.o obj/sshell.o obj/history.o obj/hash_table.o obj/variables.o
gcc -Wall -D_REENTRANT -fPIC -shared -o lib/libshell.so lib/libparser.so lib/libhistory.so \
lib/libhash_table.so lib/libvariables.so obj/shutil.o obj/parser.o obj/sshell.o obj/history.o \
obj/hash_table.o obj/variables.o
Which, it should be clear, is very not right. It's so not right I can't even really tell what you're trying to accomplish. Do you really want to create one shared library for every .o file, where each shared library contains a single .o? If so why are you trying to link both the .o files AND the shared libraries into a single executable?
If you explain what you are really trying to do, at a higher level, we can help.

Resources