How to configure a dynamic library using a macro / variable in a makefile? - makefile

I'm writing a small study project in C. I need to create a dynamic library and configure its use with macros. First, I create object files with the command:
$gcc -fPIC -c ../data_module/data_process.c
$gcc -fPIC -c ../data_libs/data_stat.c
Then I create a dynamic library like this:
$gcc -shared -o data_process.so data_process.o data_stat.o
And finally I build an executable file using this library:
$gcc main_executable_module.o ../data_libs/data_io.o ../yet_another_decision_module/decision.o -L. data_process.so -o test_main
It works and the executable works correctly. But there is a task to configure the library using macros:
Make the necessary changes to the code of the main_executable_module, configuring the use of the dynamic library using macros.
That is, if I understand correctly, you need to add macros to the main_executable_module.o so that you do not use the -L flags during assembly. But I can't find information anywhere on how to do it. Can you please tell me how to implement this or where can I read about it?
UPD: John Bollinger says
It is possible that the word "macros" is intended to be interpreted as makefile macros, which many people instead call (makefile) "variables". That would make this a question about make / makefiles, not about C.
My Makefile:
CC=gcc
LDFLAGS=
CFLAGS=-c -Wall -Wextra -Werror
SOURCES=main_executable_module.c ../data_libs/data_stat.c ../data_libs/data_io.c ../yet_another_decision_module/decision.c ../data_module/data_process.c
DYNLIB=../data_module/data_process.c
STAT=../data_libs/data_stat.c
BUILDDYN=main_executable_module.c ../data_libs/data_io.c ../yet_another_decision_module/decision.c
OBJECTS=$(SOURCES:.c=.o)
OBJBUILDDYN=$(BUILDDYN:.c=.o)
OBJDYNLIB=data_process.o
OBJDATASTAT=data_stat.o
EXECUTABLE=../../build/main
DEXECUTABLE=../../build/Quest_6
DLIBS=data_process.so
all: $(SOURCES) $(EXECUTABLE)
data_stat.a: $(OBJLIB) $(LIBS)
ar -rcs $(LIBS) $(OBJLIB)
data_process.so: $(OBJDYNLIB) $(OBJDATASTAT)
$(CC) -shared -o $(DLIBS) $(OBJDYNLIB) $(OBJDATASTAT)
$(OBJDYNLIB): $(DYNLIB)
$(CC) -fPIC -c $(DYNLIB)
$(OBJDATASTAT): $(STAT)
$(CC) -fPIC -c $(STAT)
build_with_dynamic:$(OBJECTS) $(EXECUTABLE)
$(CC) $(OBJBUILDDYN) -L. $(DLIBS) -o $(DEXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.c.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -rf $(EXECUTABLE) $(OBJECTS)
lclean:
rm -rf $(LEXECUTABLE) $(OBJECTS) $(LIBS) $(DEXECUTABLE)
rebuild: clean $(SOURCES) $(EXECUTABLE)

The results of the checks revealed nothing. There are two opinions about this task.
Leave everything as above. And in the file itself, add a header process.h. Then everything is assembled and working. And at the same time, if you change the code in the library, rebuild it, and do not rebuild the executable file, then the changes will be taken into account. That is, the idea of ​​a dynamic library is respected.
Implement in such a way that there is no need to include headers in the main_executable_module.c. Then a special library is used for working with dynamic libraries, which allows you to write the path to the library and take individual functions from it. More about it here.
What was meant when it was said about macros, I still did not understand ...

Related

What are the automatic rules make is using to build objects files without being specified?

I have an old project with several C++ source and header files in a directory which are built in cygwin using GCC and a makefile. On editing the makefile to move all the temporary and output files into a sub-directory, the rules to build the object files didnt have any effect.
$(BIN): $(OBJ)
$(CXX) $(LDFLAGS) -o $(BIN) $^
%.o: %.c
$(CXX) $(INC) $(CXXFLAGS) $# -c -o $<
The following makefile still builds the output binary without having any rules to build the object files from source code.
INC=-I.
CXX=g++
CXXFLAGS=-std=c++11 -Wall -Wextra -Wconversion -pedantic -O2 -g
LDFLAGS=
CLEAN_FILES=*.o *.out *.stackdump *.exe *.gcno *.gcda
BIN=app
SRC=$(wildcard *.cpp)
OBJ=$(SRC:%.cpp=%.o)
all: $(BIN)
$(BIN): $(OBJ)
.PHONY: clean
clean:
rm -f $(CLEAN_FILES)
What is this automatic behavior called?
Two notes regarding built-in rules:
In large projects (which will have their owner rules for compiling, linking, ....), it might be easier to start with no built-in rules (make -r or make --no-builtin-rules).
Many built-in rules have hooks, via variables, that allow configuration changes. For example:
%.o: %.c:
$(COMPILE.c) $(OUTPUT_OPTION) $<
...
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
Where opssible to customize the command by modifying "CFLAGS", "CPPFLAGS", etc. Common examples will be make "CFLAGS=-O -g" to get optimized debug program, without having to redefine all the rules.
The set of rules that make knows about without you having to define them are called built-in rules. The manual lists most of them but not all of them. You can run make -p -f/dev/null to see a list of them all.

Make File: "Nothing to be done for 'all'" Not updating after change to source file

I am brand new to make files in linux and trying to provide a make file for a simple heap management program.
When executing the make command, it works to originally build my program, however after making changes to the source file quickfit.c, make doesnt recognize the change and says "make: Nothing to be done for 'all'."
Why is it not recompiling my software after changes? I have all my source files in a source folder and all my header files in a include folder.
CC=gcc
CFLAGS= -Wall -w -g
INCLUDE:= -Iinclude/
SOURCE:= source/quickfit.c \
source/HeapTestEngine.o
EXE=QuickFit
all: $(EXE)
$(EXE):
$(CC) $(CFLAGS) $(INCLUDE) $(SOURCE) -o $(EXE)
$(EXE) doesn't depend on anything. make does not infer this dependency for you, you have to declare it.
$(EXE): $(SOURCE)
$(CC) $(CFLAGS) $(INCLUDE) $(SOURCE) -o $(EXE)
You'll probably also want to declare dependencies on your header files as well.
Note: it's a bit odd to consider an object file as "source". source/HeapTestEngine.o should probably have its own target.
Change:
$(EXE):
Into:
$(EXE): $(SOURCE)

the correct usage of `LDFLAGS` in makefile

First, the makefile in question roughly looks like this (I'm writing off my memory):
CXX=g++
CXXFLAGS=-c -Wall -std=c++11 -O3
LDFLAGS=-Wall -std=c++11 -O3
all: clean car.out
clean:
rm -f *.o *.out
car.out: a.o b.o
$(CXX) -o $# $(LDFLAGS) $^
a.o: a.cpp
$(CXX) $(CXXFLAGS) $<
b.o: b.cpp
$(CXX) $(CXXFLAGS) $<
Basically this will make some object files first and then link them together. I think this is semantically unreasonable because:
As its name suggests, LDFLAGS is for ld, but there is no flags for it here. If we need some external library like OpenGL, then a flag like -LGL is passed to g++, and then g++ would pass it to the linker. In that case, it would be reasonable to put -LGL in LDFLAGS.
Even if it's the case where we put flags such as -Wall into LDFLAGS, it doesn't make much sense. This kind of flags are intuitively for the compilation process, not linking (unless I understand this process wrong).
In https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html, there is a piece of code $(CC) -c $(CFLAGS) $(CPPFLAGS), which passes -c explicitly. I think this is the better way to do this--putting all compilation flags (e.g. -Wall) into CXXFLAGS, and pass in -c explicitly for object file compilation. Of course, the web page does not say that this piece of code is definitely better or the only way to do it.
So the only reason I can think of to use LDFLAGS there is because "there's a linking step," which doesn't make much sense to me. In my opinion, the makefile above should look like:
CXX=g++
CXXFLAGS=-Wall -std=c++11 -O3
all: clean car.out
clean:
rm -f *.o *.out
car.out: a.o b.o
$(CXX) -o $# $(LDFLAGS) $^
a.o: a.cpp
$(CXX) -c $(CXXFLAGS) $<
b.o: b.cpp
$(CXX) -c $(CXXFLAGS) $<
LDFLAGS defaults to an empty string, so we can still have it there for the linking step.
However I'm not sure if I'm right.
You are right that compilation flags have nothing to do in LDFLAGS. Just define LDFLAGS explicitly so that another editor -or yourself, when some time has passed- can figure out at a glance that 1. it is empty and 2. where to modify it (like adding -s to it, which is quite common).

How do I write a clean Makefile?

The Makefiles that I have dealt with, for the most part, are complex and hide a lot of relationships. I have never written one myself, and was wondering if anybody had some tips on writing a Makefile that is easy to read and reusable?
I usually use something like this, in this example the source files are main.c file2.c file3.c file4.c, to add more you simply add to the OBJECTS var.
They all depend on Makefile, so for a full recompile a simple touch Makefile would suffice.
PROGNAME = hi2u
LIBS = -ljpeg -ldirectfb -pthread
INCLUDES = -I/usr/local/include/directfb
LDFLAGS = -Llibs/
OBJECTS = main.o file2.o \
file3.o file4.o
CFLAGS = -W -Wall -O2 -ggdb
all: $(PROGNAME)
$(PROGNAME): $(OBJECTS)
gcc -o $(PROGNAME) $(OBJECTS) $(LIBS) $(INCLUDES) $(LDFLAGS)
$(OBJECTS): Makefile
.c.o:
gcc -c $(CFLAGS) $(INCLUDES) -o $# $<
clean:
rm *.o $(PROGNAME)
In all honesty, the complexity of a makefile relies on the complexity of the program. If you have a lot of folders and files and different compiling processes, you're makefile is probably going to be a little long and complicated. If you have a helloworld program, there's no reason for it to be longer than a few lines.
Here's some tips on makefiles : http://mrbook.org/tutorials/make/
Here's a very reusable makefile that's not too complicated:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
A tutorial that I've found helpful for understanding Makefiles is http://www.jfranken.de/homepages/johannes/vortraege/make_inhalt.en.html
Another tip is to make generous use of regular expressions for source files and dependencies
For me, the read that got me thinking about these issues, is the classic "Recursive Make Considered Harmful".
When I get the chance to create makefiles from scratch, I try to use implicit rules as much as possible, and also define rules in a separate file, which I can include from the "real" makefile.
The challenges with using make can be divided in two major groups:
issues inherent with make itself, its rich semantics and syntax and somewhat archaic appearance
issues which are not makes "fault", but come from when make is used to call another make process. Suddenly we have another task at hand - communicating between two or more make processes. It is very easy to get lost with environment variables or other ways to pass information. Platform differences which make itself is designed to hide, may become visible.

Trouble creating a makefile

I'm having some trouble making a Makefile. Write now I just compile everything every time. Although, the professor is ok with that, I do want to get it working faster and to avoid unnecessary compiling.
Here's what I have.
FILES= p6.cpp SetIter.cpp Node.cpp Set.cpp
CFLAGS= -ansi -pendantic -Wall -Wextra
CC= g++
MakePg6: p6.cpp SetIter.cpp Node.cpp Set.cpp
$(CC) $(CFLAGS) $(FILES) -o pg6
Node.cpp - node class
Set.cpp - uses nodes. Friend of Node.
SetIter.cpp - gets a set and uses a pointer to iterator through
I'm confused with some of the depencies arising from the friends thing and the point of lib.o being included in the Makefile as some sites have.
Any help is greatly appreciated. Thanks in advance.
You can simplify you make file, but using the $(FILES) in the dependency of MakePg6 thus:
MakePg6: $(FILES)
$(CC) $(CFLAGS) $(FILES) -o pg6
The friend part is resolved by each c++ is compiled independently, and the header files define all the information need to compile that one file. The compiler enforces the friend rules. The linker weaves the resulting object together to make the resulting executable.
The lib.o is include because people are making use of standard code provided by the base library. You get linking error's if you missing stuff.
What about trying to separate the making of files, so as to rebuild each one only if needed.
OBJECTS= p6.o SetIter.o Set.o Node.o
.cpp.o: $*.cpp
$(CC) $(CFLAGS) -cpp $*.cpp
p6.o: p6.cpp SetIter.cpp // any file that it depends on
SetIter.o: SetIter.cpp Set.cpp //etc
Set.o: Set.cpp Node.cpp
Node.o: Node.cpp
p6: $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o
MakePg6: p6
In doing that, it will build each object file only if the .o file is older than the .cpp file, and I think that's what you are trying to accomplish.
If your Makefile works as written, then you must have the header files (e.g. Node.h) set up correctly. So the different files can be compiled separately and linked, but whether you do that or not you must account for dependencies on the header files.
OBJECTS= p6.o SetIter.o Node.o Set.o
CFLAGS= -ansi -pendantic -Wall -Wextra
CC= g++
# This will compile any object file (something.o) that is called for
# Note that I am using automatic variables-- "$<" means the first prerequisite
# (the .cpp file), "$^" means all the prerequisites, and "$#" means the target.
%.o: %.cpp
$(CC) $(CFLAGS) -c $< -o $#
# If A.cpp (or A.h) includes B.h, then if you change B.h you must recompile A.o,
# So A.o depends on B.h.
# I will make some educated guesses about how you include header files:
SetIter.o Node.o Set.o: Node.h
Set.o: Set.h
SetIter.o p6.o: Set.h SetIter.h
# This will link the object files together to make pg6.
# Notice that the target is the name of thing actually made, a good practice.
pg6: $(OBJECTS)
$(CC) $(CFLAGS) $^ -o $#
You have to work out those .h dependencies by looking at the code. There are ways to have g++ and Make do it automatically, but that's an advanced technique.

Resources