-1

I have a C project program that I want to compile and manage with a makefile:

./include: where headers resides

a.h , b.h , c.h

./obj: where object will be stored

-

./src: where source file resides

main.c , a.c , b.c , c.c

How can I create a makefile to create an executable test , and put object files to obj folder ?

Social Programmer
  • 147
  • 1
  • 4
  • 12
  • 1
    What makefile have you tried so far? How did it not do what you wanted it to? Have you examined any online tutorials or looked through the GNU make manual at https://www.gnu.org/software/make/manual/html_node/Introduction.html? – MadScientist Mar 13 '18 at 23:23
  • Your question is pretty broad. What, specifically, is preventing you from writing a makefile such as you're after? – John Bollinger Mar 13 '18 at 23:38
  • 1
    pinam45's response should be everything you need. Two other places to look: [How to generate a Makefile with source in sub-directories using just one makefile](https://stackoverflow.com/questions/231229/how-to-generate-a-makefile-with-source-in-sub-directories-using-just-one-makefil) and [How do I make a simple makefile for gcc on Linux?](https://stackoverflow.com/questions/1484817/). PS: Please "accept" and "upvote" pinam45's answer, if you like it. – paulsm4 Mar 14 '18 at 00:40

1 Answers1

1

You can use this template I made for simple project. I don't know which compiler you are using but you can configure it with the variables in the first sections as well as other useful configs:

#=============================================================================
# Project related variables
EXENAME           = test
FILEIDENTIFIER    = .c
COMPFLAGS         = -pedantic -Wall
COMPSTANDARD      = -std=c11
EXELINKS          = -lm
DBARGS            = -g

BUILDDIR          = build/
BINARY_OUTPUT_DIR = $(BUILDDIR)bin/
OBJDIR            = obj/
SOURCEDIRS        = src/
INCLUDEDIRS       = include/
LIBSDIRS          = /usr/lib/


#=============================================================================
# Commands variables
COMPILER          = gcc
LINKER            = ld -r

DISPLAY           = printf
MKDIR             = mkdir -p
RMDIR             = rmdir
RM                = rm -f


#=============================================================================
# Other
VOIDECHO          = > /dev/null 2>&1


#=============================================================================
# Semi-automatic variables
EXEFINALOBJ       = $(OBJDIR)$(EXENAME).o
EXEFINAL          = $(BINARY_OUTPUT_DIR)$(EXENAME)
INCLUDEARGS       = $(addprefix -I,$(INCLUDEDIRS))


#=============================================================================
# Automatic variables
SOURCES           = $(foreach sourcedir,$(SOURCEDIRS),$(wildcard $(sourcedir)**/*$(FILEIDENTIFIER)) $(wildcard $(sourcedir)*$(FILEIDENTIFIER)))
OBJECTS           = $(patsubst %$(FILEIDENTIFIER),%.o,$(foreach sourcedir,$(SOURCEDIRS),$(subst $(sourcedir),$(OBJDIR),$(wildcard $(sourcedir)**/*$(    FILEIDENTIFIER)) $(wildcard $(sourcedir)*$(FILEIDENTIFIER)))))
GENERATED_FILES   = $(OBJECTS) $(EXEFINALOBJ) $(EXEFINAL)
GENERATED_FOLDERS = $(OBJDIR) $(BINARY_OUTPUT_DIR) $(BUILDDIR)


#=============================================================================
# Special GNU make variables
VPATH             = $(SOURCEDIRS)


#=============================================================================
# Rules: Phony Targets
.PHONY: silent
silent:
    @make --silent $(EXEFINAL)

.PHONY: all
all: $(EXEFINAL)

.PHONY: debug
debug: COMPFLAGS += $(DBARGS)
debug: all

.PHONY: clean
clean:
    @$(DISPLAY) "\n-> Cleaning files...\n"
    @$(DISPLAY) " $(foreach file,$(GENERATED_FILES),$(if $(wildcard $(file)),- Removing file $(file)\n,\b))"
    @$(RM) $(GENERATED_FILES)
    @$(DISPLAY) "\n-> Cleaning folders...\n"
    @$(DISPLAY) " $(foreach folder,$(GENERATED_FOLDERS),$(if $(wildcard $(folder)),- Removing folder $(folder)\n,\b))"
    @$(RMDIR) $(GENERATED_FOLDERS) $(VOIDECHO) || true
    @$(DISPLAY) "\n"


#=============================================================================
# Rules: File Targets
$(EXEFINAL): $(EXEFINALOBJ)
    @$(DISPLAY) "\n - Building $@ from $^...   "
    @$(MKDIR) $(BINARY_OUTPUT_DIR)
    $(COMPILER) $(EXEFINALOBJ) -o $@ $(LIBARGS) $(EXELINKS)
    @$(DISPLAY) "Done"
    @$(DISPLAY) "\n\n"

$(EXEFINALOBJ): $(OBJECTS)
    @$(DISPLAY) "\n - Merging objects files into $@...   "
    $(LINKER) $(OBJECTS) -o $@
    @$(DISPLAY) "Done"

$(OBJDIR)%.o: %$(FILEIDENTIFIER)
    @$(DISPLAY) "\n - Building $@ from $^...   "
    @$(MKDIR) $(OBJDIR)
    $(COMPILER) $(COMPFLAGS) $(COMPSTANDARD) $(INCLUDEARGS) -c $^ -o $@
    @$(DISPLAY) "Done"

The actual configuration is for Linux and uses gcc and ld. It support subfolders for sources and 4 targets are defined:

  • silent (default): silent build
  • all: verbose build
  • debug: debug build
  • clean: remove files and folders generated by the makefile

If you want to understand exactly how the Makefile work, as MadScientist wrote, look at the GNU make manual at https://www.gnu.org/software/make/manual/html_node/Introduction.html

pinam45
  • 589
  • 5
  • 4