Makefile can I execute a configuration only once? - c

Im trying to create a Makefile which compiles some files and creates some outputs but first I want it to execute the configuration only one time and the next time I type make it wont re-execute the configuration unless I change the parameters for example the prefix.
I tried using touch , FORCE and if, after searching a bit in other posts but Im newbie in gcc and Makefiles so I cant make it work.
My code now is (did not include the other rules because they dont affect the configuration):
XLEN := 32
RISCV_PREFIX := riscv$(XLEN)-unknown-elf-
RISCV_GCC := $(RISCV_PREFIX)gcc
CFLAGS := -O2
WORKING_DIR:= $(shell pwd)
LIBRARY_DIR:= $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..)
B := $(shell echo $(LIBRARY_DIR))
$(info $(B))
--->(execute this only once)---> CONFIGURATION := configure --prefix=$(LIBRARY_DIR) --with-arch=rv32if --with-abi=ilp32d
RISCV_TEST_DIR:=$(shell pwd)
SCRIPTDIR:=$(RISCV_TEST_DIR)/../../tools
RISCV_OPTIONS = -o
RISCV_LINK = $(RISCV_GCC) $(PROGRAMS) $(RISCV_OPTIONS) $# $(CFLAGS) #produces .elf file!
RISCV_OBJDUMP = $(RISCV_PREFIX)objdump -D #produces a dump file to see the assembly code!
RISCV_OBJCOPY = $(RISCV_PREFIX)objcopy -O binary #produces a bin file!
%.elf: %.c
$(info Generating .elf file from files: $(PROGRAMS_NO_EX))
$(RISCV_LINK)
$(info Success!)
$(info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~)
%.dump: %.elf
$(info Copying assembly to dump file $(PROGRAMS_NO_EX).dump)
#$(RISCV_OBJDUMP) $< > $#
$(info Success!)
$(info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~)
%.bin: %.elf
$(info Generating bin file)
#$(RISCV_OBJCOPY) $< $#
$(info Success!)
$(info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~)
%.hex: %.bin
$(info Generating hex file)
echo cd $(SCRIPTDIR)
$(info Running binary to hex >>>)
python $(SCRIPTDIR)/bin2hex.py $< -a 0x0 > $# || exit -1
$(info Hex Generation Successful!)
$(info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~)
all: $(PROGRAMS_TO_CREATE); if [ -a $(LIBRARY_DIR)/config.status ]; then cd $(LIBRARY_DIR) && $(CONFIGURATION); fi;
configure: config.status
touch configure
config.status:
cd $(LIBRARY_DIR) && $(CONFIGURATION);
.PHONY: all clean
clean:
$(info Cleaning files...)
#rm -rf *.elf *.hex *.map *.objdump *.i *.s *.bin *.dump
$(info Done cleaning!)
Thank you in advance!

I believe the only problem with your configuration statements are incorrect paths in rules for config.status and configure, since they really will be located within $(LIBRARY_DIR). When the paths are correct, it will correctly run configuration only once:
$ cat Makefile
LIBRARY_DIR := library
all: $(LIBRARY_DIR)/config.status
$(info Making $#)
$(LIBRARY_DIR)/config.status: $(LIBRARY_DIR)/configure
cd $(<D) && ./$(<F)
Output:
$ make
cd library && ./configure
Making all
$ make # <--- Invoking second time, no configure step
Making all
make: 'all' is up to date.

With #raspy's help managed to solve the problem like this:
all: $(PROGRAMS_TO_CREATE)
$(PROGRAMS_TO_CREATE):$(LIBRARY_DIR)/config.status
$(LIBRARY_DIR)/config.status:
cd $(LIBRARY_DIR) && $(CONFIGURATION)

Related

MS-Windows MakeFIles

I am trying to write makefile for ms-windows application. The idea is very simple. I have to generate the output .o, .exe files into the build directory. I have written makefile which will compile source directory, but is not able to generate the build directory and compilation process is perfectly working.
Please have a look for the makefile. It looks like i am not able to generate the build directory using mkdir command.
CC= gcc
CFLAG= -g -Wall
TARGET_EXEC ?= test.exe
RELEASE= Release
RELEASE_BIN= bin
RELEASE_CNFG= config
RELEASE_LOG= log
RELEASE_DATA=data
BUILD_DIR ?= build
SRC_DIRS ?= src
#OS dependent cleaning command
ifdef OS
RM = rd /s /q
else
ifeq ($(shell uname), Linux)
RM = rm -f
endif
endif
SRCS := $(wildcard $(SRC_DIRS)/*.c)
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)
INC_DIRS := $(wildcard $(SRC_DIRS) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
#find the directory for the include file
#this is best otpion to search curl directory
USR_INC := /usr/include
FILES :=
INCLUDES = -Iinclude
LIBS= -lm
CPPFLAGS ?= $(INC_FLAGS) -MMD -MP
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $# $(LIBS) $(LLFLAGS)
# c source
$(BUILD_DIR)/%.c.o: %.c
#echo Compiling $<
# here I am trying to generate the file into the build/src/xxxc.o
# $(MKDIR_P) $#
$(CC) $(CFLAG) -c $< -o $# $(INCLUDES)
.PHONY: install
install:
# echo "Installing..........."
# echo "Creating $(RELEASE) Directory..."
# $(MKDIR_P) $(RELEASE)
# echo "Creating $(RELEASE)/$(RELEASE_BIN) Directory.."
# $(MKDIR_P) $(RELEASE)/$(RELEASE_BIN)
# echo "Creating $(RELEASE)/$(RELEASE_CNFG) Directory..."
# $(MKDIR_P) $(RELEASE)/$(RELEASE_CNFG)
# echo "Creating $(RELEASE)/$(RELEASE_LOG) Directory..."
# $(MKDIR_P) $(RELEASE)/$(RELEASE_LOG)
# echo "Creating $(RELEASE)/$(RELEASE_DATA) Directory..."
# $(MKDIR_P) $(RELEASE)/$(RELEASE_DATA)
# echo "Makking Release folder ready.."
#cp $(BUILD_DIR)/$(TARGET_EXEC) $(RELEASE)/$(RELEASE_BIN)
# echo "copy certificate file to Release"
#cp -r cert $(RELEASE)
# echo "copy .ini file to Release"
#cp -r config/*.ini $(RELEASE)/$(RELEASE_CNFG)
.PHONY: clean
clean:
$(RM) $(BUILD_DIR) $(RELEASE)
-include $(DEPS)
MKDIR_P ?= mkdir
I do understand what your are trying. But please be aware that some differences in platforms and dependencies will force you to create something that is similar to a "configure" and "make" step.
So you will start to generate a custom Makefile in a tool to be invented by you sooner or later :).
It is mentioned in the comments: This has already been done and cmake is now "industrial standard"
It works on Windows, Linux, OSX and so on with great toolchain support. Have a look at it!
Example:
cmake_minimum_required(VERSION 3.4)
project(HelloWorldCMake)
set(MY_SOURCES
hello_world.c
)
add_executable(HelloWorldCMake
${MY_SOURCES}
)
And hello_world.c
#include <stdio.h>
int main()
{
printf("Hello world (cmake)");
}
If you want to link additional libraries, please research
the CMake command: target_link_libraries
https://cmake.org/cmake/help/latest/command/target_link_libraries.html

ld: can't open output file for writing [duplicate]

I'm trying to compile my code on OSX El Capitan. This is my Makefile
TARGET = proj_name
CC = gcc
# compiling flags
CFLAGS = -std=c99 -Wall -I.
LINKER = gcc -o
# linking flags
LFLAGS = -Wall -I. -lm
SRCDIR = src
OBJDIR = obj
BINDIR = bin
SOURCES := $(wildcard $(SRCDIR)/*.c)
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
rm = rm -f
$(BINDIR)/$(TARGET): $(OBJECTS)
#$(LINKER) $# $(LFLAGS) $(OBJECTS)
#echo "Linking complete!"
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
#$(CC) $(CFLAGS) -c $< -o $#
#echo "Compiled "$<" successfully!"
.PHONEY: clean
clean:
#$(rm) $(OBJECTS)
#echo "Cleanup complete!"
.PHONEY: remove
remove: clean
#$(rm) $(BINDIR)/$(TARGET)
#echo "Executable removed!"
I keep getting the following error while compiling on El Capitan
ld: can't open output file for writing: bin/proj, errno=2 for architecture x86_64
I understand that its a linker issue, but if someone could help me amending the Makefile, it would really help.
Errno 2 means (google for something like errno list):
#define ENOENT 2 /* No such file or directory */
bin/proj is relative path.
Looking at the Makefile, the most likely cause seems to be, bin directory simply does not exist. ld will not try create it if it is not there. To fix, add
mkdir -p $(BINDIR)
before $(LINKER) line (-p switch allows creating a path if it does not exist, which in this case prevents error if bin already exists).
A side note: Another common cause with relative paths is, that working directory is not what you think it is, when ld is run. Adding command like pwd to before $(LINKER) command would help troubleshooting this. But looking at Makefile, this probably is not the reason here.

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.

Make error when trying to create *.o

I'm at my wits end here because of this extremely stupid error I'm getting from my makefile.
I finally gave up stripped the makefile down to just two lines:
%.o: %.c
gcc -c -o $# $< -I../inc
Command: make . The output:
make: *** No targets. Stop.
The spaces at the beginning are real tabs instead of spaces. The c files are in the same directory. If instead of %.o I give, say, file1.o and file1.c instead of %.c, all is well (file1.o gets created). I see plenty of examples on the 'net that use the % operator, though. If I include a clean: target, it is promptly found, like so:
%.o: %.c
gcc -c -o $# $< -I../inc
clean:
echo "this is clean!"
Command: make . The output:
echo "this is clean!"
this is clean!
Please help me out here as I'm totally clueless about what's wrong with my targets. In the second sample (the one with clean target), I guess the clean target is found and acted upon as the first one is 'invalid' somehow.
Looks like you forgot to write a target. You have just written rules of how to compile, but not what to do with those objects. I mean, I miss something like:
my_executable_file: *.o
gcc -o my_executable_file *.o
EDIT:
What is set before is true, you need a target. But as you want only to compile, your target should be something like:
OBJECTS = file.o #and whatever objects you need, as a list separated by commas
And then your target:
my_objects: $(OBJECTS)
So putting it all together:
OBJECTS = file.o #and whatever objects you need, as a list separated by commas
my_objects: $(OBJECTS)
%.o: %.c
gcc -c -o $# $< -I../inc
Below is the Makefile that will enable to any number of targets to compile
OBJ := file.o
all: $(OBJ)
%.o: %.c
gcc -c -o $# $< -I../inc
clean:
echo "this is clean!"
Here, OBJ will be the list of the files that you want to compile , like here it is file.c
Add the file name you want to compile to OBJ, when make is called it will build the target all first which depends on the OBJ.
To build OBJ the gcc command is used.
When an explicit target is not given to make, then the first (non-pattern?) target in the Makefile is used. In the case above, it is the clean target.
I see your intention to make only .o files (can be needed for creation of libraries).
You can modify your Makefile to build only .o files or build only executable by using the same Makefile
For the below directory structure (using tree command)
# tree .
.
|-- include
| `-- head.h
|-- Makefile
|-- obj
`-- src
`-- main.c
Makefile
# GNU Makefile #
# Some Variables #
CC := gcc
RM := rm
MV := mv
# Phony Targets #
.PHONY: clean
.PHONY: move
# Path for Source, Object and Include #
SRC_PATH := ./src/
OBJ_PATH := ./obj/
INCLUDE_PATH := ./include/
# Source and Object File Names #
SRC := $(SRC_PATH)main.c
OBJ := $(SRC:c=o) # Substitutes all SRC but with .c as .o (main.c becomes main.o) #
# Executable Name #
TARGET := exe
# Building Binary - use 'make' #
binary: $(TARGET) move
$(TARGET): $(OBJ)
$(CC) -o $(TARGET) $^
# Building only Object Files - use 'make object_only' #
object_only : $(OBJ) move
$(OBJ): $(SRC)
$(CC) -c -o $# $< -I $(INCLUDE_PATH)
# This rule is for moving .o files to ./obj directory (More Organised) #
move:
$(MV) $(SRC_PATH)*.o $(OBJ_PATH)
# For Cleaning - use 'make clean' #
clean:
echo "Cleaning Up!"
$(RM) -rfv $(TARGET) $(OBJ_PATH)*.o $(SRC_PATH)*.o # Delete .o and executable #
Execution:
To build only object files use
$ make object_only
To build object files and executable, use
$ make

Resources