Appropriate Makefile to replace a gcc compile/link run? - c

My goal is to use a single Makefile for compiling a C app across various platforms.
I've been busily relearning C while working on a project, so as a result have not yet had the time to delve into make; instead I have a single, long gcc command in some .bat / .sh files. Needless to say that each time I change one such file, I have to make those same changes in the others. Hence, make. Conditions that need to be handled:
Builds for multiple OS & architecture, i.e. for now (at least) 32 & 64-bit for Windows & Linux, thus I need access to that info in the Makefile, and executables should go into distinct folders under /build: i.e. /win32, /win64, /lin32, /lin64 (et cetera, in future).
Required DLLs should be copied in alongside the built executable.
Separate compile & link phases (thanks #EtanReisner)
Question: Can someone show me how one would go about constructing a Makefile using the info below? And explain how each part works / why it is needed for my particular case? I have an understanding of the prerequisites approach by which Makefiles are built. Thanks in advance.
Here is my project directory tree:
+---bin
+---include
| +---enet
| +---GL
| +---libxml
| \---ncursesw
+---lib
+---src
+---fonts
\---shaders
And mingw gcc for Windows 32-bit compile:
gcc -Iinclude ./src/main.c ./src/MainCtrl.c ./src/MainView.c ./src/PerspectiveView.c ./src/LogView.c ./src/LobbyView.c ./src/TerminalView.c ./src/World.c ./src/Chunk.c ./src/CellPattern.c ./src/CellPlan.c ./src/GridPoint.c ./src/Entity.c ./src/InfluenceRadial.c ./src/AoIList.c ./src/AoI.c ./src/ChunkRenderable.c ./src/PrimitiveRenderable.c ./src/Geometry.c ./src/glew/glew.c ./src/stb/stb_image_aug.c ../curt/list_generic.c ../curt/map_generic.c ../curt/intMap.c ../curt/floatMap.c ../hedgehog/hedgehog.c ./src/Inputs.c ./src/InputResponse.c ./src/Network.c ../Disjunction/c/disjunction.c ./src/my/math/Range.c ./src/my/math/Point.c -Llib -lglfw3-32 -lopengl32 -lgdi32 -lenet-32 -lws2_32 -lwinmm -llibxml2-32 -L. -ldll32/libncursesw6 -std=c11 -m32 -w -Wall -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wstrict-prototypes -Wlogical-op -Wcast-align -Wconversion -Wpedantic -Wfloat-equal -fopenmp -O0 -o ./build/win32/wa
And the gcc for Linux 64-bit compile:
gcc -Iinclude -I/usr/include/libxml2 ./src/main.c ./src/MainCtrl.c ./src/MainView.c ./src/PerspectiveView.c ./src/LogView.c ./src/LobbyView.c ./src/TerminalView.c ./src/World.c ./src/Chunk.c ./src/CellPattern.c ./src/CellPlan.c ./src/GridPoint.c ./src/Entity.c ./src/InfluenceRadial.c ./src/AoIList.c ./src/AoI.c ./src/ChunkRenderable.c ./src/PrimitiveRenderable.c ./src/Geometry.c ./src/glew/glew.c ./src/stb/stb_image_aug.c ../curt/list_generic.c ../curt/map_generic.c ../curt/intMap.c ../curt/floatMap.c ../hedgehog/hedgehog.c ./src/Inputs.c ./src/InputResponse.c ./src/Network.c ../disjunction/c/disjunction.c ./src/my/math/Range.c ./src/my/math/Point.c -Llib -L/usr/lib -l:libglfw.so.3 -lncurses -lGL -lxml2 -lenet -lm -std=c11 -m64 -w -Wall -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wstrict-prototypes -Wlogical-op -Wcast-align -Wconversion -Wpedantic -Wfloat-equal -fopenmp -g -o ./wa-64.elf
(worth diffing these.)

Trial and error led tothe following... work in progress, but the basics are there. Features:
No need to manually list source / object files (all relevant sources expected to be in src)
Separate compile & link phases using shared logic for .c/.o file lists
OS & architecture autodetection (WIP), with manual override for arch (
e.g. make BITS=32)
Clean that works for both Win & *nixes
Copies in .DLLs on compile (WIP to supply a list of DLLs to copy in)
Thanks to Yanick Rochon, Samuel and Trevor Robinson for their answers, and to those who wrote the GNU Makefile examples.
CC = gcc
#Directories
HDRDIR = include
SRCDIR = ./src
OBJDIR = ./obj
BINDIR = ./bin
LIBDIR = lib
#File lists
HDRS := $(wildcard $(HDRDIR)/*.h)
SRCS := $(wildcard $(SRCDIR)/*.c)
OBJS := $(SRCS:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
#Autodetect OS / architecture
OS =
BITS = 32
#ifeq ($(shell echo "check_quotes"),"check_quotes")
ifeq ($(OS),Windows_NT)
OS := win
EXT := .exe
rm := del /q
cp := copy /y
ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
CFLAGS += -D AMD64
endif
ifeq ($(PROCESSOR_ARCHITECTURE),x86)
CFLAGS += -D IA32
endif
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
OS := lin
EXT := .elf
rm := rm -f
cp := cp
CCFLAGS += -D LINUX
BITS = $(shell getconf LONG_BIT)
endif
ifeq ($(UNAME_S),Darwin)
OS := osx
EXT :=
rm := rm -f
cp := cp
CCFLAGS += -D OSX
BITS = $(shell getconf LONG_BIT)
endif
UNAME_P := $(shell uname -p)
ifeq ($(UNAME_P),x86_64)
CCFLAGS += -D AMD64
endif
ifneq ($(filter %86,$(UNAME_P)),)
CCFLAGS += -D IA32
endif
ifneq ($(filter arm%,$(UNAME_P)),)
CCFLAGS += -D ARM
endif
endif
#Define flags for compile & link
CFLAGS = -I$(HDRDIR) -std=c11 -m64 -fopenmp -Wall -Werror -Wmissing-prototypes -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wlogical-op -Wcast-align -Wconversion -Wpedantic -Wfloat-equal -w -O0 -DGLEW_STATIC
LFLAGS = -L$(LIBDIR)
#Do we want verbose linker messages?
LVERBOSE := false
LLIBS =
ifeq ($(OS),win)
LLIBS += -lglfw3-$(BITS) -lglew32s -lglew32 -lopengl32 -lgdi32 -lwinmm
endif
ifeq ($(OS),lin)
LLIBS += -lglew32s -lglew32 -lGL -lm
endif
ifeq ($(LVERBOSE),true)
LFLAGS += -Wl,--verbose
endif
TARGET = program$(EXT)
#Rules
$(BINDIR)/$(TARGET): $(OBJS)
#$(CC) -o ./$# $(OBJS) $(LFLAGS) $(LLIBS)
#echo Linking complete.
#$(cp) $(LIBDIR)\glfw3.dll $(BINDIR)
#echo DLLs accompanying executable.
$(OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
#$(CC) $(CFLAGS) -c $< -o ./$#
#echo Compiled $<.
.PHONEY: clean
clean:
ifeq ($(OS),win)
#$(rm) $(subst /,\\,$(OBJS))
#$(rm) $(subst /,\\,$(BINDIR)/*.*)
else
#$(rm) $(OBJS)
#$(rm) $(BINDIR)/*
endif
#echo Cleanup complete.
#$(subst /,\\, $(SOMETHING)) replaces all (make-native) forward slashes with backslashes, for Windows.

Related

GNU make doesn't include headerfile

I have been searching for 6 hours and I can't seem to find the issue with this GNU make file, everytime I try to compile by main.o by the order
make main.o
it gives me this error:
arm-none-eabi-gcc -c main.c -mcpu=cortex-m4 -mthumb --
specs=nosys.specs -Wall -Werror -g -O0 -std=c99 -o main.o
main.c:23:22: fatal error: platform.h: No such file or directory
#include "platform.h"
^
compilation terminated.
Makefile:52: recipe for target 'main.o' failed
make: *** [main.o] Error 1
makefile:
include sources.mk
# Platform Overrides
PLATFORM = MSP432
# Architectures Specific Flags
LINKER_FILE = msp432p401r.lds
CPU = cortex-m4
ARCH = thumb
SPECS = nosys.specs
# Compiler Flags and Defines
CC = arm-none-eabi-gcc
LD = arm-none-eabi-ld
TARGET = c1m1
LDFLAGS = -Wl,-Map=$(TARGET).map -T $(LINKER_FILE)
CFLAGS = -mcpu=$(CPU) -m$(ARCH) --specs=$(SPECS) -Wall -Werror -g -O0 -std=c99
CPPFLAGs =
.PHONY: all
all: $(TARGET).out
.PHONY: clean
clean:
rm -f $(OBJS) $(TARGET).out $(TARGET).map
%.o : %.c
$(CC) -c $< $(CFLAGS) -o $#
OBJS = $(SOURCES:.c=.o)
$(TARGET).out: $(OBJS)
$(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) -o $#
sources.mk:
# Add your Source files to this variable
SOURCES =./main.c \
./memory.c \
./startup_msp432p401r_gcc.c \
./system_msp432p401r.c \
./interrupts_msp432p401r_gcc.c
# Add your include paths to this variable
INCLUDES =-I./include/CMSIS \
-I./include/common \
-I./include/msp432
here's my code on github:
github repository
You have not used the INCLUDES macro in makefile's CFLAGS macro. Consequently the arm-none-eabi-gcc ... command line does not specify the include paths to the compiler (or strictly the pre-processor).
CFLAGS = -mcpu=$(CPU) -m$(ARCH) --specs=$(SPECS) $(INCLUDES) -Wall -Werror -g -O0 -std=c99
^^^^^^^^^^^

Add OpenCL CL/cl.h path to existing Make file

I am trying to successful execute a make file that comes from a new crytpo-coin called Sia Coin. It can be found here Sia Coin GPU Miner. It's relatively new and so some stuff requires more manual installation. I was getting the following error on Ubuntu 16.04 when using the make file. CL/cl.h was missing, and I was able to install and it is located at /usr/include/nvidia-361/CL/cl.h. However, when I ran the make file I still get errors so I think I need to include this path someone in the Make file, the problem is I am not familiar with make files at all. Below is the Make file I need to edit to include the path for compilation:
ifeq ($(shell uname -s),Darwin)
CC ?= clang
LDLIBS += -lcurl -framework OpenCL
else
CC ?= gcc
LDLIBS += -lOpenCL -lcurl
endif
CFLAGS += -c -std=c11 -Wall -pedantic -O2
TARGET = sia-gpu-miner
SOURCES = sia-gpu-miner.c network.c
OBJECTS = $(patsubst %.c,%.o,$(SOURCES))
all: $(TARGET)
%.o: %.c
$(CC) $(CFLAGS) -o $# $<
$(TARGET): $(OBJECTS)
$(CC) -o $# $^ $(LDLIBS)
clean:
rm -f $(TARGET) $(OBJECTS)
.PHONY: all clean
Any help toward solving this problem is greatly appreciated.
Edit:
A new message I am getting now adding
CFLAGS += -c -std=c11 -Wall -pedantic -O2 -I /usr/include/nvidia-361
is now:
-lOpenCL -lcurl /usr/bin/ld: cannot find -lOpenCL collect2: error: ld returned 1 exit status
Two files did compile:
sia-gpu-miner.c
network.c
But I don't know enough to know why the -lOpenCL is not found. No ld directory exists in that directory location in the error if that helps.
Try changing
CFLAGS += -c -std=c11 -Wall -pedantic -O2
to
CFLAGS += -c -std=c11 -Wall -pedantic -O2 -I /usr/include/nvidia-361

Makefile conditional statements not working

I have the following makefile code where the ifeq statement is not evaluating to true and I don't understand why not:
PROCESSOR=`uname -p`
ifeq ($(strip $(PROCESSOR)), x86_64)
PROCESSOR = -c -march=atom -fPIC -Wall -I../../inc
else
PROCESSOR = -c -march=i386 -fPIC -Wall -I../../inc
endif
I have confirmed on my system that uname -p results in "x86_64", but the ifeq statement is evaluating to false and PROCESSOR is being set to -c -march=i386 -fPIC -Wall -I../../inc. I have also tried ifeq "$(strip $(PROCESSOR))" "x86_64" and a few variations without the strip function. Anyone have any suggestions?
Backticks aren't command execution in a makefile.
Add $(info $(PROCESSOR)) above the ifeq line to see what I mean.
You want:
PROCESSOR=$(shell uname -p)
$ cat Makefile
PROCESSOR=`uname -p`
$(info backticks: $(PROCESSOR))
PROCESSOR=$(shell uname -p)
$(info $$shell: $(PROCESSOR))
$ make
backticks: `uname -p`
$shell: x86_64

stm32 arm-none-eabi-gcc link library

Hello I need to compute logarithms on my stm32. I use arm-none-eabi-gcc. When I add -L/opt/tools/Sourcery_G++_Lite/arm-none-eabi/lib/ in my Makefile microcontroller stop to work. Unfortunately I can't debug my program because there is no debag pins on my device and I load program to flash via bootloader. I not use any math functioins from libraries - i just add library path to Makefile.
Here is my full makefile:
OUTPUTDIR = $(BUILDDIR)/../../output
DEPDIR = $(BUILDDIR)/.dep
PWD = $(shell pwd)
COMMONFLAGS = -mcpu=cortex-m3 -mthumb -ggdb3
CFLAGS += $(COMMONFLAGS) -Os $(INCLUDES) -I.
CFLAGS += -std=c99 -Wall -Wextra -static -fdata-sections -ffunction-sections -fno-hosted -fno-builtin
CFLAGS += -nostdlib -nodefaultlibs
CFLAGS += -mapcs-frame -msoft-float
CFLAGS += -MD -MP -MF $(DEPDIR)/$(#F).d
LDFLAGS = $(COMMONFLAGS) -static
LDFLAGS += -fno-exceptions -ffunction-sections -fdata-sections
LDFLAGS += -static -Xlinker --gc-sections
#LDFLAGS += -L/opt/tools/dima/Sourcery_G++_Lite/arm-none-eabi/lib/
ASFLAGS = $(COMMONFLAGS)
CFLAGS += -DUSE_STDPERIPH_DRIVER
CROSS = /opt/tools/Sourcery_G++_Lite/bin/arm-none-eabi
GCC = $(CROSS)-gcc
AS = $(CROSS)-as
SIZE = $(CROSS)-size
OBJCOPY = $(CROSS)-objcopy
OBJDUMP = $(CROSS)-objdump
NM = $(CROSS)-nm
COBJ = $(addprefix $(BUILDDIR)/, $(CSRC:.c=.c.o))
ASMOBJ = $(addprefix $(BUILDDIR)/, $(ASMSRC:.s=.s.o))
OBJ = $(COBJ) $(ASMOBJ)
V = $(if $(VERBOSE), , #)
all: prebuild $(BUILDDIR)/$(TARGET).elf $(LDSCRIPT)
#$(SIZE) $(BUILDDIR)/$(TARGET).elf
#$(OBJCOPY) -O binary $(BUILDDIR)/$(TARGET).elf $(BUILDDIR)/$(TARGET).bin
#$(OBJCOPY) -O ihex $(BUILDDIR)/$(TARGET).elf $(BUILDDIR)/$(TARGET).hex
#$(OBJDUMP) -h -S -z $(BUILDDIR)/$(TARGET).elf > $(BUILDDIR)/$(TARGET).lss
#$(NM) -n $(BUILDDIR)/$(TARGET).elf > $(BUILDDIR)/$(TARGET).sym
#mkdir -p $(OUTPUTDIR)
#cp $(BUILDDIR)/$(TARGET).bin $(OUTPUTDIR)
#echo =======================================================================
$(BUILDDIR)/$(TARGET).elf: $(OBJ)
#echo Linking $#
$(GCC) $(LDFLAGS) -T $(PWD)/$(LDSCRIPT) -o $# $(OBJ) -lm
$(COBJ): $(BUILDDIR)/%.c.o : %.c
#echo Compiling $<
#-mkdir -p $(#D)
$(GCC) $(CFLAGS) -c $< -o $#
$(ASMOBJ): $(BUILDDIR)/%.s.o : %.s
#echo Assembling $<
#-mkdir -p $(#D)
$(V)$(AS) $(ASFLAGS) -c ./$< -o $#
-include $(shell mkdir -p $(DEPDIR) 2>/dev/null) $(wildcard $(DEPDIR)/*)
.PHONY: clean output
clean:
rm -rf $(BUILDDIR)
What i do wrong? Thanks.
Whith this library dir you will simply link against the wrong set of files in multilib, and end up linking with ARM code while your MCU can only execute THUMB code. The correct set of files should be in the thumb2 subdirectory for Cortex M3 µC.
Note that Sourcery G++ lite will auto-magically add the correct library dir when using arm-none-eabi-gcc to link, which your Makefile seems to do already.
You really shouldn't link libm.a manually and you really shouldn't hardcode library path manually... This all gets done automatically (and correctly) if you use arm-none-eabi-gcc (or -g++) to link and give proper flags (-mcpu and -mthumb). So just drop all these paths and "-lm" and it must work. You could try one of my example project for ARM microcontrollers - the settings in the makefiles (and linker scripts) make all of this work just fine - with no user intervention. http://www.freddiechopin.info/en/download/category/6-examples
Also - I think part of the problem may be in these flags you use: -fno-hosted -fno-builtin -nostdlib -nodefaultlibs - the last one especially prevents this automatic linking of libm.a.

Makefile not working for multiple c files but works for single c file

This makefile is for making hex file for an ARM micro-controller. My makefile takes all the c files kept in the folder and generates the hex file. The hex file, .obj files etc. are placed in the bin folder.
My makefiles works fine(i.e I am able to see the hex file, .obj files etc.) when there is only one c file inside the folder. But if I place more than one c file in the folder, build fails. Below is the error what I get when I have more than one c file.
arm-none-eabi-gcc: error: main.o: No such file or directory
make: *** [32bitTimer.elf] Error 1
I am attaching my makefile for reference.
Could you please let me know why it doesn't work for multiple c files ?
## makefile
BINARY = 32bitTimer
LDSCRIPT = stm32f4-discovery.ld
SRCS = $(wildcard *.c)
OBJDIR = bin
PREFIX = arm-none-eabi
CC = $(PREFIX)-gcc
LD = $(PREFIX)-gcc
OBJCOPY = $(PREFIX)-objcopy
OBJDUMP = $(PREFIX)-objdump
GDB = $(PREFIX)-gdb
TOOLCHAIN_DIR ?= ../libopencm3
CFLAGS += -Os -g \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I$(TOOLCHAIN_DIR)/include \
-fno-common -mcpu=cortex-m4 -mthumb \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -MD -DSTM32F4
LDFLAGS += --static -lc -lnosys -L$(TOOLCHAIN_DIR)/lib \
-L$(TOOLCHAIN_DIR)/lib/stm32/f4 \
-T$(LDSCRIPT) -nostartfiles -Wl,--gc-sections \
-mthumb -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16
OBJS = $(SRCS:.c=.o)
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := #
endif
all: $(OBJDIR) $(BINARY).images
%.images: %.elf
$(Q)$(OBJCOPY) -Obinary $(OBJDIR)/$(*).elf $(OBJDIR)/$(*).bin
$(Q)$(OBJCOPY) -Oihex $(OBJDIR)/$(*).elf $(OBJDIR)/$(*).hex
$(Q)$(OBJCOPY) -Osrec $(OBJDIR)/$(*).elf $(OBJDIR)/$(*).srec
$(Q)$(OBJDUMP) -S $(OBJDIR)/$(*).elf > $(OBJDIR)/$(*).list
$(BINARY).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f4.a
$(Q)$(LD) -o $(OBJDIR)/$(BINARY).elf $(OBJDIR)/$(OBJS) -lopencm3_stm32f4 $(LDFLAGS)
%.o:%.c
$(Q)$(CC) $(CFLAGS) -o $(OBJDIR)/$# -c $<
$(OBJDIR):
$(Q)mkdir $(OBJDIR)
clean:
$(Q)rm -rf $(OBJDIR)
.PHONY: images clean
This is probably the most direct problem: On the line that starts $(Q)$(LD) -o $(OBJDIR) you have the text:
$(OBJDIR)/$(OBJS)
This does not do what you (seem to) expect. This just appends the string value of $(OBJDIR) to the string value of $(OBJS). It isn't actually prefixing each word in the latter. You probably want instead to say this:
$(patsubst %,$(OBJDIR)/%,$(OBJS))
which will prefix each word in $(OBJS) with the value of $(OBJDIR) followed by a slash.

Resources