Home > Blockchain >  How can I make my makefile put my project together the way I need it?
How can I make my makefile put my project together the way I need it?

Time:04-21

I've been through probably 20 different webpages about makefile but I still can't seem to get it to work for my project. A project with all the files in one folder works, but I can't get it to work with my specific project which has everything in different folders.

Example structure

Here is an example project that has all the necessary features and distinctions to be structurally identical to my project yet obviously smaller:

.
|-- bin
|   |-- foo_apple (executable 1)   // needs apple's .o files (C  )
|   |-- foo_banana (executable 2)  // needs banana's .o files   .so file (C/C  )
|-- include
|   |-- format
|   |   |-- format.h
|   |-- apple
|   |   |-- foo.h
|   |-- banana
|       |-- bar.h
|-- lib
|   |-- apple
|   |   |-- apple_main.o
|   |   |-- apple_one.o
|   |-- banana
|   |   |-- banana_main.o
|   |   |-- banana_one.o
|   |   |-- banana_two.o
|   |-- archive_apple
|   |   |-- libapple_one.a
|   |-- archive_banana
|   |   |-- libbanana_one.a
|   |   |-- libbanana_two.a
|   |-- external
|   |   |-- foo.so
|-- makefile
|-- src
    |-- drivers
    |   |-- apple_main.cpp       // needs format.h
    |   |-- banana_main.cpp    // needs format.h,
    |-- apple
    |   |-- apple_one.cpp        // needs format.h, foo.h
    |-- banana
        |-- banana_one.c       // needs format.h, bar.h
        |-- banana_two.cpp     // needs format.h, bar.h

I've been reading about things online about automatic makefile generation, where you type in certain things into the makefile that goes through the folders and uses substitutions and other things to eliminate the need to list every single rule explicitly, but none of them worked. I must be doing something wrong, but I don't know what it is.

What I need

I want to put the correct things into my makefile that creates what you see above.

As you can see, some parts of the project are necessarily written in C. (I guess I could change everything to be C but I don't want to if I don't have to).

My compilers and flags will be:

CC := gcc
CXX := g  
C_FLAGS := -Wall -std=c17
CXX_FLAGS := -Wall -std=c  17

My directories will use -I to avoid things like

// #include "../../include/format/format.h"
// instead:
#include <format/format.h>

I'll also be using -L, if that helps, because I want to create those .a files. As far as I can see, it's something like:

libsomething.a: something.o
    ar rvs ./lib/archive/libsomething.a ./lib/foo/something.o

What do I need in my makefile in order to put this project together and generate my executables, object files, and libraries?

Note: I understand the basics of makefile, like how a rule works and how to put together a makefile manually for a small and simple project, but I'm only just starting to understand the built-in functions and wildcards and other complex things.

And of course, since my project is much larger than this, though structurally identical, I need the answer to be something either generic or easy to modify, like those examples of makefiles I saw online that for some reason don't work on my project. That way, I can adapt this to future projects without unnecessary manual work.

Preferably (unless it is bad practice to do so), I would like for the executables to be built from the libraries, something along the lines of:

executable: something_main.o libfoo.a libbar.a
    $(CXX_BUILD) -o ./bin/executable \
    ./lib/something_main.o \
    -L./lib/something \
    -lfoo -lbar

CodePudding user response:

Ad 1 and 2: The filenames can safely include directories and % matches / as necessary. So you can easily have:

$(wildcard subdir/*.c) $(wildcard anotherdir/*.c)

or even

$(wildcard */*.c)

... or as suggested by keltar in comment

$(shell find . -name '*.c')

which is recursive.

Ad 3: You are doing it.

Ad 4: Create a target with $(OBJ) as dependencies and use the automatic variable just as you do for compilation:

main : $(OBJ)
        $(LD) $(LDFLAGS) -o $@ $< $(LIBS)

Original answer by @Jan Hudec: make for compiling — all *.c files in folders & subfolders in project

CodePudding user response:

May Help.

The Structure of the project:

    xc
        inc
        src
    test
        inc
        src
    obj
        xc
        test
    bin

Makefile

PNAME = xc
OBJS_DIR=obj
BIN_DIR=bin
INC_SUB_DIR=inc
SRC_SUB_DIR=src

CPP = gcc
#CPP  = -m32

#LIBPATH = -Llib
LIBLIST  = -lz
LDFLAGS  = $(LIBPATH) $(LIBLIST) 

UTILS_DIR = xc
UTILS_SRCS  = $(wildcard $(UTILS_DIR)/$(SRC_SUB_DIR)/*.c)
UTILS_INCS  = $(wildcard $(UTILS_DIR)/$(INC_SUB_DIR)/*.h)
UTILS_SLIST = $(UTILS_SRCS) $(UTILS_INCS)
UTILS_OLIST = $(wildcard $(OBJS_DIR)/$(UTILS_DIR)/*.o)
UTILS_OBJS  = $(patsubst $(UTILS_DIR)/$(SRC_SUB_DIR)/%.c,$(OBJS_DIR)/$(UTILS_DIR)/%.o,$(UTILS_SRCS))

BASE_DIR = test
BASE_SRCS  = $(wildcard $(BASE_DIR)/$(SRC_SUB_DIR)/*.c)
BASE_INCS  = $(wildcard $(BASE_DIR)/$(INC_SUB_DIR)/*.h)
BASE_SLIST = $(BASE_SRCS) $(BASE_INCS)
BASE_OLIST = $(wildcard $(OBJS_DIR)/$(BASE_DIR)/*.o)
BASE_OBJS  = $(patsubst $(BASE_DIR)/$(SRC_SUB_DIR)/%.c,$(OBJS_DIR)/$(BASE_DIR)/%.o,$(BASE_SRCS))

SLIST  = $(UTILS_SLIST) $(BASE_SLIST)
OLIST  = $(UTILS_OLIST) $(BASE_OLIST)
OBJS  = $(UTILS_OBJS) $(BASE_OBJS)

INCPATH = -I$(UTILS_DIR)/$(INC_SUB_DIR) -I$(BASE_DIR)/$(INC_SUB_DIR)
CPPFLAGS  = -c -Wall -Wextra
#CPPFLAGS  = -O2
CPPFLAGS  = $(INCPATH)
#CPPFLAGS  = -g 

# target
.PHONY = all

all: $(PNAME)

packsrc:
    tar zcvf $(PNAME)-src-`date  %Y%m%d%H%M%S`.tgz $(SLIST) doc Makefile 

slib:
    $(AR) rcs $(PNAME)-`date  %Y%m%d%H%M%S`.a $(OBJS)

clean:
    $(RM) $(OLIST) $(BIN_DIR)/$(PNAME)
 
$(PNAME): $(OBJS) 
    @ mkdir -p $(BIN_DIR)
    @ mkdir -p $(OBJS_DIR)
    @ mkdir -p $(OBJS_DIR)/$(UTILS_DIR)
    @ mkdir -p $(OBJS_DIR)/$(BASE_DIR)
    $(CPP) $^ -o $(BIN_DIR)/$@ $(LDFLAGS)

$(OBJS_DIR)/$(UTILS_DIR)/%.o:$(UTILS_DIR)/$(SRC_SUB_DIR)/%.c
    $(CPP) $(CPPFLAGS) $< -o $@

$(OBJS_DIR)/$(BASE_DIR)/%.o:$(BASE_DIR)/$(SRC_SUB_DIR)/%.c
    $(CPP) $(CPPFLAGS) $< -o $@

dos2unix:
    dos2unix $(SLIST)  
  • Related