Hi I have a makefile like this:
# Variables =====================================================================================
PHONY =
proj =
ALL_FILES := $(filter $(proj).%,$(shell ls | grep "^$(proj)\.[a-z]*$$"))
LEX_FILE := $(filter %.l, $(ALL_FILES))
BISON_FILE := $(filter %.y, $(ALL_FILES))
C_FILE := $(filter %.c, $(ALL_FILES))
H_FILE := $(filter %.h, $(ALL_FILES))
BISON_OUT_H := $(subst .y,.tab.h,$(BISON_FILE))
BISON_OUT_C := $(subst .y,.tab.c,$(BISON_FILE))
BISON_OUT := $(BISON_OUT_C) $(BISON_OUT_H)
LEX_OUT := $(subst .l,.yy.c,$(LEX_FILE))
LEX_TRG := $(LEX_FILE)
LEX_DEP := $(LEX_FILE) $(BISON_OUT_H)
GCC_TRG := $(BISON_OUT_C) $(LEX_OUT) $(C_FILE)
GCC_DEP := $(GCC_TRG) $(H_FILE) $(BISON_OUT_H)
CFLAGS = -g
test:
#echo $(proj)
#echo $(ALL_FILES)
#echo $(LEX_FILE)
#echo $(BISON_FILE)
#echo $(C_FILE)
#echo $(BISON_OUT_C)
#echo $(LEX_OUT)
#echo $(GCC_TRG)
#echo $(GCC_DEP)
# Flex ==========================================================================================
$(LEX_OUT):$(LEX_DEP)
ifneq (,$(LEX_TRG))
flex --outfile=$# $(LEX_TRG)
endif
# Bison =========================================================================================
$(BISON_OUT):$(BISON_FILE)
ifneq (,$(BISON_FILE))
bison -d $<
endif
# Run ===========================================================================================
$(proj).out:$(GCC_DEP)
ifneq (,$(GCC_TRG))
gcc $(CFLAGS) $(GCC_TRG) -o $#
endif
run:$(proj).out
./$<
run_lex:$(proj).out
#echo "Please type in file names: "; \
read file; \
./$< $$file
PHONY += run run_wc run_lex
# Clean =========================================================================================
clean:
-rm *.out *.lex *.yy.c *.tab.h *.tab.c *.s
cleansp:
-rm $(proj).out $(proj).lex $(BISON_OUT) $(LEX_OUT)
PHONY += clean cleansp
# GitHub ========================================================================================
commit: clean
git add -A
#echo "Please type in commit comment: "; \
read comment; \
git commit -m"$$comment"
sync: commit
git push -u origin master
PHONY += commit sync
# PHONY =========================================================================================
.PHONY: $(PHONY)
In the current folder I have
[shore#shore-82b6 flex-bison]$ ls
calc2.c calc2.h calc2.l calc2.tab.c calc2.tab.h calc2.y calc2.yy.c calc.l calc.y ccr.l lc.l makefile Note.md samples st.l wc.l
The thing vary confused me is that when I run make run proj=calc2, if calc.y is changed then the make file will run extra instructions and output to calc.c as a result. The following is the shell output:
[shore#shore-82b6 flex-bison]$ make run proj=calc2
bison -d calc2.y
flex --outfile=calc2.yy.c calc2.l
yacc calc2.y
mv -f y.tab.c calc2.c
calc2.yy.c calc2.tab.c calc2.c
Notice this will only happen if calc.y is changed.
So how should I fix this and letting the makefile run the instructions suppose to be in my makefile.
You are being bitten by one of make's built-in rules:
%.c: %.y
# recipe to execute (built-in):
$(YACC.y) $<
mv -f y.tab.c $#
This says, "if I have a file foo.y and I want to build a file foo.c, here's how to do it". This is the normal naming convention for building yacc files.
In your situation you have a file calc2.y which is the yacc file and another file calc2.c which is a normal source file, but make doesn't know that it's a normal source file.
If you want to have your calc2.y not be related to your calc2.c, and instead have calc2.y be related only to calc2.tab.c, you'll have to cancel the built-in rule by declaring it without any recipe like this:
%.c: %.y
Related
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
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.
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)
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.
This is the main part of my makefile:
#openmp
ifeq($(BLITTZ_CC), icc)
OPENMP_OPTIONS := -fopenmp
else
OPENMP_OPTIONS := -fopenmp
endif
#compiler options
CXXFLAGS := -WALL -Wno-unused-parameter $(OPTIMIZE_OPTIONS) $(OPENMP_OPTIONS) $(MODE)
SRC_LIST := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_LIST := $(patsubst %.cpp, $(BUILD_DIR)/%.o, $(notdir $(SRC_LIST)))
TARGET := main
BIN_TARGET := $(BIN_DIR)/$(TARGET)
$(BIN_TARGET): $(OBJ_LIST)
$(BLITZ_CC) -o $# $(OBJ_LIST) $(CXXFLAGS)
$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.s
$(BLITZ_CC) -o $# -c $< $(CXXFLAGS)
$(BUILD_DIR)/%.s: $(SRC_DIR)/%.cpp
$(BLITZ_CC) -o $# -S $(CXXFLAGS) $<
#inc test
test:
echo $(SRC_LIST)
echo $(OBJ_LIST)
echo $(BIN_TARGET)
#clean
clean:
find $(BUILD_DIR) -name *.o -exec rm rf {} \;
find $(BUILD_DIR) -name *.s -exec rm rf {} \;
rm $(BIN_DIR)/*
This is what happens after make:
Why does rm *.s occur here? I need the assemble files and I do not want to delete them.
Because you've chained rules to create your .o files from your .cpp files, make marked your .s files as intermediate files and deleted them after building your target:
[...] an intermediate file which did not exist before make also does not exist after make.
You need to either mark your files as secondary files:
.SECONDARY: $(OBJ_LIST:.o=.s)
When a file is secondary, make will not create the file merely because it does not already exist, but make does not automatically delete the file.
Or you can flag your file pattern as precious:
.PRECIOUS: %.s
You can list the target pattern of an implicit rule (such as ‘%.o’) as a prerequisite of the special target .PRECIOUS to preserve intermediate files made by implicit rules whose target patterns match that file’s name; [...]
find $(BUILD_DIR) -name *.s -exec rm rf {} \; will get all .s files and execute rm rf so delete that line if you want to keep .s files