Platform conditional makefiles - c

I am trying to make my Makefiles platform conditional with statements like:
ifeq ($(UNAME), Linux)
# LINUX version
program_NAME := lib$(TARGET).so
OBJDIR = ../build/linux
endif
ifeq ($(UNAME), MINGW32_NT-6.1)
# WINDOWS version
program_NAME := lib$(TARGET).dll
OBJDIR = ../build/windows
endif
and:
ifeq ($(UNAME), Linux)
# LINUX version
program_INCLUDE_DIRS := \
/home/ben/projects/g2/src \
/home/ben/projects/pulse_IO/src \
/home/ben/projects/core/src
endif
ifeq ($(UNAME), MINGW32_NT-6.1)
# WINDOWS Virtual Machine version
program_INCLUDE_DIRS := \
E:/g2/src \
E:/pulse_IO/src \
E:/core/src
endif
I then compile the src either under Linux or Windows 7 running as a VM (via virtualbox) on a Linux host OS. Problem I haven't managed to solve is how to get the object files and resulting shared libraries or executables to be written to a platform specific directory, e.g. /build/linux or /build/windows where the source code is in /src
As you can see I've added an OBJDIR variable but I can't figure out how to use that to redirect the .o, .so, .dll, .exe files to the correct dir conditional on platform. I'm sure it should be easy but my research keeps bogging down with articles on vpath usage which I don't think is what I'm after.
The part of my Makefile I think I need to modify is as follows:
LINK.c := $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
$(program_NAME): $(program_OBJS)
$(LINK.c) -shared -Wl,-soname,$(program_NAME) $(program_OBJS) -o $(program_NAME)
I should probably be using something smarter like autotools or cmake but it would be great just to get this working for now.
should also add, my list of object files is created as follows:
program_C_OBJS := ${program_C_SRCS:.c=.o}
Have tried:
program_OBJS := $(addprefix $(OBJDIR)/$program_C_OBJS)
but make compains that addprefix has the wrong no. of arguments

For gmake, see Here:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)

What compiler and toolset are you using? In the case of QNX, it has macros like:
$OS
$CPU
$PRODUCT
$PROJECT
$SECTION
$VARIANT ($VARIANTLIST, $EXCLUDE_VARIANTLIST)
These allow you to customize the target folder and filename for the results of your build.
http://www.qnx.com/developers/docs/6.3.2/neutrino/prog/make_convent.html
Other compilers/toolchains have similar facilities.

Related

Breakpoints are not being hit - CLion Full Remote Debug - MakeFile - GDB

It doesn't matter what type of remote debug connection I tried.. Full Remote Host, Remote Debug, Remote GDB Server etc.
Actually remote device starts working when I clicked the debug button. I can run it from my CLion but it never hits to my breakpoints..
I'm not professional on remote debugging, actually it is my second work but this time it is on already working ( readymade ) project on my Raspberry pi Lorawan device ( Debian ) .
Device connected to my home network and there is a package forwarder app in it. App listens 1680 port.
Normally it is working on remote device with no problem. I downloaded the app to my computer and built the project successfully in CLion. After I tried lots of things, almost every combination of remote debugging and settings. I understood I'm missing some point and I need help. If you can help me you will save my life
Makefile :
### get external defined data
include ../target.cfg
### Application-specific constants
APP_NAME := lora_pkt_fwd
### Environment constants
LGW_PATH ?= ../libloragw
LIB_PATH ?= ../libtools
ARCH ?=
CROSS_COMPILE ?=
OBJDIR = obj
INCLUDES = $(wildcard inc/*.h)
### External constant definitions
# must get library build option to know if mpsse must be linked or not
include $(LGW_PATH)/library.cfg
RELEASE_VERSION := `cat ../VERSION`
### Constant symbols
CC := -g $(CROSS_COMPILE)gcc
AR := $(CROSS_COMPILE)ar
CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. -I../libtools/inc
VFLAG := -D VERSION_STRING="\"$(RELEASE_VERSION)\""
### Constants for Lora concentrator HAL library
# List the library sub-modules that are used by the application
LGW_INC =
ifneq ($(wildcard $(LGW_PATH)/inc/config.h),)
# only for HAL version 1.3 and beyond
LGW_INC += $(LGW_PATH)/inc/config.h
endif
LGW_INC += $(LGW_PATH)/inc/loragw_hal.h
### Linking options
LIBS := -lloragw -ltinymt32 -lparson -lbase64 -lrt -lpthread -lm -lcursor
### General build targets
all: $(APP_NAME)
clean:
rm -f $(OBJDIR)/*.o
rm -f $(APP_NAME)
ifneq ($(strip $(TARGET_IP)),)
ifneq ($(strip $(TARGET_DIR)),)
ifneq ($(strip $(TARGET_USR)),)
install:
#echo "---- Copying packet_forwarder files to $(TARGET_IP):$(TARGET_DIR)"
#ssh $(TARGET_USR)#$(TARGET_IP) "mkdir -p $(TARGET_DIR)"
#scp lora_pkt_fwd $(TARGET_USR)#$(TARGET_IP):$(TARGET_DIR)
install_conf:
#echo "---- Copying packet_forwarder conf files to $(TARGET_IP):$(TARGET_DIR)"
#ssh $(TARGET_USR)#$(TARGET_IP) "mkdir -p $(TARGET_DIR)"
#scp global_conf.json.sx1250.* $(TARGET_USR)#$(TARGET_IP):$(TARGET_DIR)
#scp global_conf.json.sx1257.* $(TARGET_USR)#$(TARGET_IP):$(TARGET_DIR)
else
#echo "ERROR: TARGET_USR is not configured in target.cfg"
endif
else
#echo "ERROR: TARGET_DIR is not configured in target.cfg"
endif
else
#echo "ERROR: TARGET_IP is not configured in target.cfg"
endif
### Sub-modules compilation
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: src/%.c $(INCLUDES) | $(OBJDIR)
$(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $#
### Main program compilation and assembly
$(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) $(INCLUDES) | $(OBJDIR)
$(CC) -c $(CFLAGS) $(VFLAG) -I$(LGW_PATH)/inc $< -o $#
$(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a $(OBJDIR)/jitqueue.o
$(CC) -L$(LGW_PATH) -L$(LIB_PATH) $< $(OBJDIR)/jitqueue.o -o $# $(LIBS)
### EOF
I'm sharing my last try screenshots with you : Full Remot Host.
If I add -g to CXXFLAGS in https://github.com/remonbonbon/makefile-example, I can debug the app target just fine.
link -> https://intellij-support.jetbrains.com/hc/en-us/community/posts/360009699119-Debugging-not-working-when-using-the-Makefile-feature-in-2020-2-EAP-

filter-out is not filtering file? Makefile for C

so ive got a make file here and my project currently has a master.c and slave.c which both have main functions. therefore i just want to filter the slave.c file out of the building process. so I used fliter-out when defining the source files. but when run make the project keeps turning up with the "multiple definitions of main" error. why is this when filter-out should be hiding the slave.c file?
########################################################################
####################### Makefile Template ##############################
########################################################################
#Compiler settings - Can be customized.
CC = gcc
CXXFLAGS = -std=c11 -Wall
LDFLAGS =
# Makefile settings - Can be customized.
APPNAME = master
SUBAPPNAME = slave
EXT = .c
SRCDIR = .
OBJDIR = .
############## Do not change anything from here downwards! #############
SRC := $(filter-out slave.c, $(wildcard $(SRCDIR)/*$(EXT)))
OBJ := $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)/%.o)
DEP := $(OBJ:$(OBJDIR)/%.o=%.d)
#UNIX-based OS variables & settings
RM = rm
DELOBJ = $(OBJ)
# Windows OS variables & settings
DEL = del
EXE = .exe
WDELOBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)\\%.o)
########################################################################
####################### Targets beginning here #########################
########################################################################
all: $(APPNAME)
# Builds the app
$(APPNAME): $(OBJ)
$(CC) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
# Creates the dependecy rules
%.d: $(SRCDIR)/%$(EXT)
#$(CPP) $(CFLAGS) $< -MM -MT $(#:%.d=$(OBJDIR)/%.o) >$#
# Includes all .h files
-include $(DEP)
# Building rule for .o files and its .c/.cpp in combination with all .h
$(OBJDIR)/%.o: $(SRCDIR)/%$(EXT)
$(CC) $(CXXFLAGS) -o $# -c $<
################### Cleaning rules for Unix-based OS ###################
# Cleans complete project
.PHONY: clean
clean:
$(RM) $(DELOBJ) $(DEP) $(APPNAME)
# Cleans only all files with the extension .d
.PHONY: cleandep
cleandep:
$(RM) $(DEP)
# Clean only all files with the extension .o
.PHONY: cleanobj
cleanobj:
$(RM) $(DELOBJ)
# Cleans both files with .d and .o extensions
.PHONY: cleanod
cleanod:
$(RM) $(DELOBJ) $(DEP)
The call
SRC := $(filter-out slave.c, $(wildcard $(SRCDIR)/*$(EXT)))
is just a string operation, that is, make is unaware of the underlying file tree and tries to throw out the string slave.c from the liste yoursrcdir/slave.c yoursrcdir/master.c which obviously fails. Although you may disagree at first, this is a good thing because the semantic of filter operations on filetrees is by no means universal or easy to document or transport. Therefore make just looks at the presented strings and decides on the character-for-character comparison which to take and which to drop.
That said, the rewrite to
SRC := $(filter-out $(SRCDIR)/slave.c, $(wildcard $(SRCDIR)/*$(EXT)))
will do the trick in your case.
For wider reaching functionality look up the two functions abspath and realpath to get file names in a canonical format, which prevent filter et.al. from stumbling on differences in OS nomenclature.

makefile with gcc returns fatal error: no input files

I am trying to create a makefile for a new project. the project contains so far just some basic main func and some funcs declarations.
my makefile makes objects from source files, but no executable is compiled. exit with error:
mkdir -p build/./src/app/
gcc -std=gnu99 -Wall -I./src -I./src/app -I./src/include -I./src/lib -c src/app/main.c -o build/./src/app/main.o
mkdir -p build/./src/app/
gcc -std=gnu99 -Wall -I./src -I./src/app -I./src/include -I./src/lib -c src/app/Emsg.c -o build/./src/app/Emsg.o
gcc -std=gnu99 -Wall -I./src -I./src/app -I./src/include -I./src/lib -o bin/Main
gcc: fatal error: no input files
compilation terminated.
Makefile:59: recipe for target 'all' failed
make: *** [all] Error 1
this is my make file:
CFLAGS := -std=gnu99 -Wall
ifeq ($(STRIP), yes)
CFLAGS := $(CFLAGS) -s
endif
BUILD_DIR := ./build
BIN_DIR := ./bin
SRC_DIRS := ./
SRC_APPS := ./src
SRC_TESTS := ./test
SRCS_APPS := $(shell find $(SRC_APPS) -name '*.c')
SRCS_TESTS := $(shell find $(SRC_TESTS) -name '*.c')
OBJS_APPS := $(SRCS_APPS:%.c=$(BUILD_DIR)/%.o)
OBJS_TESTS := $(SRCS_TESTS:%.c=$(BUILD_DIR)/%.o)
OBJS_ALL := $(OBJS_APPS)
OBJS_ALL_TESTS := $(OBJS_ALL) $(OBJS_TESTS)
INC_APPS_DIRS := $(shell find ./src -type d)
INC_INCLUDES := src/include
INC_TESTS_DIRS := test/
INC_APPS_FLAGS := $(addprefix -I,$(INC_APPS_DIRS))
INCLUDE_ALL := $(INC_APPS_FLAGS)
CC := gcc
ifeq ($(TEST), yes)
CFLAGS := $(CFLAGS) -D TEST
OBJECTS := $(OBJS_APPS) $(OBJS_TESTS)
INCLUDE := $(INC_TESTS_LIBS_FLAGS) $(INC_TESTS_FLAGS)
DEPEND_LST := apps tests
COMP_ARGS := $(CC) $(CFLAGS) $(INCLUDE) $(OBJECTS) -L$(INC_TEST_LIBS) -o bin/Test
else
DEPEND_LST := apps
COMP_ARGS := $(CC) $(CFLAGS) $(INCLUDE_ALL) $(OBJECTS) -o bin/Main
endif
# All
all: $(DEPEND_LST)
$(COMP_ARGS)
#Tests
tests: $(OBJS_TESTS)
$(BUILD_DIR)/%.o: %.c
$(MKDIR_P) $(dir $#)
$(CC) $(CFLAGS) $(INCLUDE_ALL) -c $< -o $#
# Apps
apps: $(OBJS_APPS)
$(BUILD_DIR)/%.o: %.c
$(MKDIR_P) $(dir $#)
$(CC) $(CFLAGS) $(INCLUDE_ALL) -c $< -o $#
# Clean
clean:
$(RM) -r $(BUILD_DIR)
# not sure what these two lines do..
-include $(DEPS)
MKDIR_P ?= mkdir -p
I'm simply running make.
files hierarchy is:
src dir
app dir (contains main.c and more files)
include dir (contains some .h files)
lib dir (empty)
test dir (contains another main.c file)
Makefile file
Install GNU remake and run remake -X.
It will put you into a debugger and then you can run step to see step by step what the makefile is doing. Here is that applied to your Makefile:
$ remake -X
Reading makefiles...
Updating makefiles...
Updating goal targets...
-> (/tmp/so/Makefile:45)
all: apps
remake<0> step
File 'all' does not exist.
File 'apps' does not exist.
Must remake target 'apps'.
Successfully remade target file 'apps'.
<- (/tmp/so/Makefile:56)
apps
remake<1> where
=>#0 apps at Makefile:56
#1 all at Makefile:45
remake<3> x OBJS_APPS
Makefile:17 (origin: makefile) OBJS_APPS := ...
See the link for videos. Or https://github.com/rocky/remake for some screen shots
Make's output presents the commands it runs. For a serial build, at least, this unambiguously communicates what command produced each diagnostic message emitted. In your case, the command that caused the error immediately preceeds it in the output:
gcc -std=gnu99 -Wall -I./src -I./src/app -I./src/include -I./src/lib -o bin/Main
So what's wrong with that? Why, exactly what the diagnostic says: it doesn't specify any input files to operate upon. No C source files to compile, no object files or libraries to link. Nothing from which to build the designated output file.
Supposing that you've presented a complete makefile that produces the problem for you, that command must come from an attempt to build target all via this rule:
all: $(DEPEND_LST)
$(COMP_ARGS)
That's a bit suspicious on its face, because an all target typically provides only a prerequisite list, not a recipe. Each prerequisite that may need to be built would then have its own rule. But it's not inherently wrong to provide a recipe, and we need to consider the recipe itself to determine the nature of your problem. In this case, we have suspicious point #2: the recipe is specified entirely via a single variable. But I already knew that, because I had to trace through that to identify this rule as the source of the error in the first place.
In particular, the only place where the text bin/Main appears in the makefile is in this else block:
else
DEPEND_LST := apps
COMP_ARGS := $(CC) $(CFLAGS) $(INCLUDE_ALL) $(OBJECTS) -o bin/Main
endif
That indeed provides the command line variable referenced by the all target (and by nothing else), and it matches up cleanly with the command that causes the error. And what do we find when we match the bits of the command line to the variables from which that version of COMP_ARGS is built? We find that all the bits are covered by variables other than OBJECTS, which evidently expands to nothing (you can even see the separate leading and trailing space characters around its empty value). And why does OBJECTS expand to an empty value? Because it is never set when that branch of the conditional is exercised.
Personally, I would be inclined to rewrite the whole makefile to be more idiomatic and to rely less on GNU make extensions, but the simplest way forward would probably be to put an appropriate definition of the OBJECTS variable in the else block I pointed out.

"No rule to make target" althoug the rule exists

I have an issue with my makefile which says No rule to make target /obj/%.o, needed by /bin/exec. Stop. But from what I understand I have it:
# define the C compiler to use
CC = gcc
# define any compile-time flags
# add -DDEBUG for debug mode
CFLAGS = -Wall
# define any directories containing header files
INCLUDES = -I/includes
# define src folder
SRC_FOLDER = /src
# define src files
SRC = $(wildcard $(SRC_FOLDER)/%.cpp)
# define object folder
OBJ_FOLDER = /obj
# define obj files
OBJ = $(patsubst %.cpp, %.o, $(SRC))
# define binary path
BIN_FOLFER = /bin
# define the executable file
MAIN = $(BIN_FOLFER)/exec
# compile object files
$(OBJ_FOLDER)/%.o: $(SRC_FOLDER)/%.cpp
$(CC) $(CFLAGS) $< -o $#
# build
$(MAIN): $(OBJ_FOLDER)/%.o
$(CC) $(CFLAGS) $^ -o $#
# cleaning
.PHONY: clean
clean:
rm -f $(OBJ_FOLDER)/%.o
I am sorry for any possible major errors in the makefile, this is my first makefile. What am I doing wrong?
$(MAIN): $(OBJ_FOLDER)/%.o
requests %.o exactly. The % does not act as pattern here, because it does not appear on both sides of the rule. You need to use the $(OBJ) variable there. But it first need to be fixed, because you are only replacing the extension, but you need to replace the directory too.
Finish the $(OBJ) variable (as Lutin already said) (ok, but I modified it a bit; I presume you only want the direct descendants of the directory):
SRC = $(wildcard $(SRC_FOLDER)/*.cpp)
OBJ = $(patsubst $(SRC_FOLDER)/%.cpp, $(OBJ_FOLDER)/%.o, $(SRC))
Fix the rule to actually use the $(OBJ) variable:
$(MAIN): $(OBJ)
Oh, and you most probably don't want SRC_FOLDER, OBJ_FOLDER and BIN_FOLDER to start with / as that puts them in the filesystem root it's not where your project lives. And with the patterns above they should not end with slash either.
It works with that:
SRC = $(wildcard $(SRC_FOLDER)*/*.cpp $(SRC_FOLDER)*.cpp)
OBJ = $(patsubst $(SRC_FOLDER)%.cpp, $(OBJ_FOLDER)%.o, $(SRC))

compile headers dependencies with makefile

I am programming an UDP client server application in the C programming language; I want to automatically compile 2 sources files and 3 header files whenever the dependencies change so I decided to use the make utility.
The makefile target is called "edit" :
edit : server_UDP.o client_UDP.o \
gcc -o edit server_UDP.o client_UDP.o \
client_UDP.o : client_UDP.c cliHeader_UDP.h wrapHeader.h
gcc -c client_UDP.c
server_UDP.o : server_UDP.c servHeader_UDP.h wrapHeader.h
gcc -c server_UDP.c
It doesn't trigger a recompile when I change a few lines of code in wrapHeader.h.
How do to I modify the edit makefile rule(s) when there is a change in wrapHeader.h to recompile server_UDP and client_UDP ?
**note : wrapHeader.h is the main header
cliHeader_UDP.h : include "wrapHeader.h"
servHeader_UDP.h : include "wrapHeader.h"
I think what you want are Make dependency files.
You can specify the compiler to generate a dependency file for you with the '-MMD -MP' arguments, which create a new file with the same name as the source file except with the extension *.d, in the same folder as your source.
The dependency file contains all the headers the code depends on, which will lead to GNU make compiling your source file if a header it uses is modified.
An example dependency file enabled makefile:
# Makefile
CC := gcc
LD := g++
# The output executable.
BIN := program
# Toolchain arguments.
CFLAGS :=
CXXFLAGS := $(CFLAGS)
LDFLAGS :=
# Project sources.
C_SOURCE_FILES := mysourcefile1.c src/myothersrc.c
C_OBJECT_FILES := $(patsubst %.c,%.o,$(C_SOURCE_FILES))
# The dependency file names.
DEPS := $(C_OBJECT_FILES:.o=.d)
all: $(BIN)
clean:
$(RM) $(C_OBJECT_FILES) $(DEPS) $(BIN)
rebuild: clean all
$(BIN): $(C_OBJECT_FILES)
$(LD) $(C_OBJECT_FILES) $(LDFLAGS) -o $#
%.o: %.c
$(CC) -c -MMD -MP $< -o $# $(CFLAGS)
# Let make read the dependency files and handle them.
-include $(DEPS)
This should work for your situation:
SOURCES := server_UDP.c client_UDP.c
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
DEPS := $(OBJECTS:.o=.d)
edit: $(OBJECTS)
gcc -o edit $(OBJECTS)
%.o: %.c
gcc -c $< -o $#
-include $(DEPS)
You did not say that edit.c includes your two specific headers, but I guess it must, if it links to the objects.
This is exactly the scenario where makepp plays out one of its strengths: If you follow the convention that for every .o file you need to link there is an include statement of a corresponding name (in your case that would be client_UDP.h & server_UDP.h) then makepp will figure everything out itself, besides detecting the header files as dependencies.
This even works recursively, so if you had a wrapHeader.c (where there is no corresponding include statement in edit.c), that would get automatically compiled and linked.
So you don't need a makefile. But if you want to avoid calling makepp edit everytime, then you can create a one-liner
edit:
You will only need to learn make syntax, if you have more complex requirements. But if you do, there is no limit. Besides doing almost all that GNU make can, there are lots more useful things, and you can even extend your makefiles with some Perl programming.

Resources