0

Till now, I was using the following makefile that I have generated somehow for my school projects:

my makefile

But now I have a different situation: I am supposed to compile 4 programs for one project, while part of the code is supposed to be compiled as .so, for use for the 4 programs. like described here:

my project's dependencies

1 - all the parts that are supposed to be compiled together as one .so file, using for example:

gcc -shared -fPIC src/file1.c src/file2.c src/file3.c -o libutils.so

3,4,5 should be compiled and linked together with this .so file, using for example:

gcc src/file4.c -L'pwd' lutils -o file4.out

the same way for all the 3 projects, and one more simple compilation of project 2.

I wandered across the net, google, your site, etc. tried to find a solution for this situation, without any luck.

already seen solutions like this one: solution example where you supply makefile with the details of the entire project structure.

I thought about dividing all the files into 4 folders, below the main folder, and creating a loop inside makefile that will compile each program in each cycle, with "if" statements to make a different compilation, according to the index. but I had no luck, it seems very complicated (maybe someone can show me a solution like that one...).

I am wondering if there is a way of making this whole compilation process generic and automatic like the current file (maybe little less),

if there is a way, I would like to study and discover it.

thank you in advance!!! Arie

  • 1
    stackoverflow is not a free coding service. Suggest you produce the desired makefile, then ask us why it produces something other than what you want. – user3629249 Dec 01 '19 at 23:36
  • in your referenced makefile, regarding: `CFLAGS = -Wall` visual studio uses significantly different compile options than linux. For linux suggest `CFLAGS := -Wall -Wextra -Wconversion -pedantic` Note the use of `:=` because when only `=` is used, then the macro is re-evaluated each time it is referenced – user3629249 Dec 01 '19 at 23:48
  • hello @user3629249, As I mentioned in the post, I made lot's of effort trying to understand how to do it myself, took almost a couple of days, almost a week till I finally decided to reach for help, posted a detailed post about the topic, the things I already checked, etc. I don't think it's an appropriate response to someone that is reaching for help. have a good day :) i don't think that it's – Arie Charfnadel Dec 05 '19 at 08:59
  • It seems that your not familiar with the `make` facility. Please read [make Manual in PDF](https://www.gnu.org/software/make/manual/make.pdf). It is a large read, with a LOT of information – user3629249 Dec 05 '19 at 18:45

1 Answers1

1

Since you have a nicely drawn tree of dependencies, you "just" need to translate this into a Makefile.

You might like to start with this:

.PHONY: all

all: reloader.exe block_finder.exe formatter.exe printdb.exe

MODULES = reloader block_finder formatter printdb linked_list bitcoin file_handler
SRCS = $(MODULES:%=%.c)

reloader.exe block_finder.exe formatter.exe printdb.exe: libbitcoin_manager.so

reloader.exe: reloader.o
block_finder.exe: block_finder.o
formatter.exe: formatter.o
printdb.exe: printdb.o

libbitcoin_manager.so: linked_list.o bitcoin.o file_handler.o
    gcc -shared -fPIC $^ -o $@

%.exe: %.o
    gcc $< -L. -lbitcoin_manager -o $@

%.o: %.c
    gcc -c $< -o $@

%.d: %.c
    gcc -MM -MT $@ -MT $*.o -MF $@ $<

include $(SRCS:%.c=%.d)

Because you don't have a loop in the diagram, you don't need a loop in the Makefile. Instead you put all dependent files on the left of a colon and the file they depend on on the right.

You might like to collect more "objects" in variables, for example the programs to build, the modules in the library, and so on.

I have also used a common pattern to generate the dependencies from the header files. The way shown is just one way to do it. It uses files with a ".d" extension, for "dependency." GCC has options to build these files, it scans the source and collects all included headers even if "stacked."

For example, "bitcoin.d" looks like this:

bitcoin.d bitcoin.o: bitcoin.c bitcoin.h linked_list.h definitions.h \
 file_handler.h

The re-generate the dependency file on changes in the sources it is also a target, not only the object file.


EDIT:

First, using directories makes Makefiles more difficult. I don't like such structures not only for that reason, but also because they separate header files and implementation files that clearly belong to each other.

Anyway, here is an enhanced Makefile:

.PHONY: all

SRCDIR = src
INCDIR = include
BLDDIR = build

APPS = reloader block_finder formatter printdb
MODULES = reloader block_finder formatter printdb linked_list bitcoin file_handler
LIBNAME = bitcoin_manager
LIBMODULES = linked_list bitcoin file_handler

VPATH = $(SRCDIR)

SRCS = $(MODULES:%=%.c)
LIB = $(LIBNAME:%=lib%.so)
#win LIB = $(LIBNAME:%=%.lib)
EXES = $(APPS:%=%.exe)

all: $(BLDDIR) $(EXES)

$(BLDDIR):
    mkdir $@

$(LIB): $(LIBMODULES:%=$(BLDDIR)/%.o)
    gcc -shared -fPIC $^ -o $@

$(EXES): $(LIB)

$(EXES): %.exe: $(BLDDIR)/%.o
    gcc $< -L. -l$(LIBNAME) -o $@

$(BLDDIR)/%.o: %.c
    gcc -I$(INCDIR) -c $< -o $@

$(SRCDIR)/%.d: %.c
    gcc -I$(INCDIR) -MM -MT $@ -MT $(BLDDIR)/$*.o -MF $@ $<

include $(SRCS:%.c=$(SRCDIR)/%.d)

It uses a lot more variables to simplify renaming and managing a growing library and application.

One important issue is the use of VPATH. This makes make search for sources in the list of paths assigned to it. Make sure you understand it thoroughly, search for articles and documentation. It is easy to use it wrong.

The pattern $(EXES): %.exe: $(BLDDIR)/%.o is a nice one. It consists of three parts, first a list of targets, second a generic pattern with a single target and its source. Here is means that for all executables each of them is built from its object file.

Now to your questions:

  1. Is answered by the new proposal. I didn't add the directory but use VPATH.

  2. Make stopped not because the exe-from-o pattern was wrong, but because it didn't find a way to build the object file needed. This is solved by the new proposal, too. To find out what happens if you delete these 4 recipes in the old proposal: you can experiment, so do it!

  3. The dot is, like user3629249 tried to say, the present working directory. You had it in your Makefile with 'pwd' and I replaced it. This is not special to make, it is common in all major operating systems, including Windows. You might know .. which designates the parent directory.

  4. When make starts it reads the Makefile or any given file. If this file contains include directives the files listed are checked if they need to be rebuild. make does this even if you call it with -n! After (re-)building all files to be included they are included finally. Now make has all recipes and continues with its "normal" work.

the busybee
  • 10,755
  • 3
  • 13
  • 30
  • hello friend! :) – Arie Charfnadel Dec 05 '19 at 08:23
  • hello friend! :) First of all, I am sorry it took me some time to respond, I am during a crazy week, hardly breathing! And also I took the time to explore the solution in depth. About the solution that you proposed, for starters, I like it! it seems very generic and automatic, but I have a couple of difficulties and a couple of things that I didn't understand, if you can help me with them it will be awesome! :) I will write the questions in the next comment. – Arie Charfnadel Dec 05 '19 at 08:48
  • 1. All of my src files are inside "src" Dir, and include files in "include" Dir, I added this line and changed SRCS accordingly: SRCDIR="src" SRCS = $(SRCDIR\MODULES:%=%.c) it seems that it's being recognized. 2. When I try to compile, I get " make: *** No rule to make target 'reloader.o', needed by 'reloader.exe'. Stop. I think that it's because of the 4 recipes like "reloader.exe: reloader.o" that have no rule, and they cause make skip: "%.o: %.c not", ..... will continue in the next comment..... – Arie Charfnadel Dec 05 '19 at 08:55
  • how can I solve it? because if I delete these 4 recipes, the make will try to compile the modules of SO as well, no? 3. Another thing, for what is the purpose of the dot (".") inside the rule "gcc $< -L. -lbitcoin_manager -o $@" ? 4. I have a problem following the flow after the "%.o: %.c" rule, it seems that the dependency is on *.c files, but the next rule is for *.d files that themselves depend on *.c files, can you please explain what happens during the run-time, how and when? what is the flow? and also in which step happens the include? and what it causes? – Arie Charfnadel Dec 05 '19 at 08:55
  • regarding: `%.o: %.c` This should be: `%.o: %.c %.d` so the dependency files are included – user3629249 Dec 05 '19 at 18:57
  • the `-L.` says to look for the libraries (besides the usual places) in the current directory – user3629249 Dec 05 '19 at 19:08
  • a makefile is examined by `make` and ordered by dependencies. The actual execution order of the `rules` is by `make` executing each `rule` when all its' dependencies are 'satisfied'. `make` uses the 'date' of each dependency file to determine if a specific `rule` needs to be executed. – user3629249 Dec 05 '19 at 19:15
  • each `rule` has zero or more, indented via tab, lines below it. Those indented lines are the `recipe` (steps) to be executed when that `rule` needs to be executed. – user3629249 Dec 05 '19 at 19:20
  • @user3629249 No, it's wrong to write `%.o: %.c %.d` because object files don't depend on the dependency files. – the busybee Dec 06 '19 at 07:08
  • @ArieCharfnadel Please give me some time, I'm really busy as well. – the busybee Dec 06 '19 at 07:08
  • @thebusybee, The 'make' utility needs to be able to recognize when any of those `#included` files have changed as that would require a re-compile. Therefore, the *.d is a required dependency – user3629249 Dec 06 '19 at 16:32
  • @user3629249 That's right, but object files depend on their source files and the `#included` *header* files, not the *dependency* files. Did you look into such a file? It contains a pattern for the object file's recipe for `make`. The object file does *not* depend on the dependency file because it is not included in its source file. – the busybee Dec 07 '19 at 14:51