Is there a way to conditionally include a sub-Makefile based on the result of a an ifeq test as suggested below
CC = g++
CENTOS_VERSION := $(shell rpm -E %{rhel})
TARGET = main
$(TARGET): $(TARGET).cpp
ifeq ($(CENTOS_VERSION),6)
#echo "Building on CentOS 6"
include(CentOS6_Makefile.mk)
else
#echo "Building on CentOS 7"
include(CentOS7_Makefile.mk)
endif
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).cpp
This does not work and generates the error message
Building on CentOS 6
include(CentOS6_Makefile.mk)
/bin/sh: -c: line 0: syntax error near unexpected token `CentOS6_Makefile.mk'
/bin/sh: -c: line 0: `include(CentOS6_Makefile.mk)'
make: *** [main] Error 1
Based on the answer by #MadScientist the solution to my problem boils down to just 2 lines
CENTOS_VERSION := $(shell rpm -E %{rhel})
include CentOS$(CENTOS_VERSION)_Makefile.mk
Your problem is not related to ifeq; if you remove the ifeq and always include one or the other you'll see the same problem.
First, your syntax for including files is wrong. There are no parentheses around filenames in make's include directive. It should just be:
include CentOS6_Makefile.mk
Second, you cannot use makefile processor commands like include as part of a recipe (that is, indented by a TAB). In a make recipe ALL lines that indented by TAB are passed to the shell as commands to run to build the target, they are not interpreted by make (except to expand macros). Also, you cannot include some other makefile in the middle of a recipe: once make starts to include a new makefile that's the end of any recipe that is currently being defined.
You can do this:
CENTOS_VERSION := $(shell rpm -E %{rhel})
ifneq ($(CENTOS_VERSION),6)
CENTOS_VERSION := 7
endif
include CentOS$(CENTOS_VERSION)_Makefile.mk
$(TARGET): $(TARGET).cpp
#echo "Building on CentOS $(CENTOS_VERSION)"
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).cpp
Related
I have a problem with a makefile that's part of a repository. I already posted this question but don't know how to add some code lines after, so I'm trying it here.There is a problem with the makefile that has the common make rules. When I run make, I get the following error: C:\Mios32/include/makefile/common.mk:143: *** multiple target patterns. Stop.
Here's the code from common.mk file from line 142 to 144:
# rule to create .elf file
$(PROJECT_OUT)/$(PROJECT).elf: $(ALL_OBJS)
#$(CC) $(CFLAGS) $(ALL_OBJS) $(LIBS) $(LDFLAGS) -o$#
I'm guessing it's a problem with all_objs, cause these lines right before seem to work:
# rule to create a .hex and .bin file
%.bin : $(PROJECT_OUT)/$(PROJECT).elf
#$(OBJCOPY) $< -O binary $#
%.hex : $(PROJECT_OUT)/$(PROJECT).elf
#$(OBJCOPY) $< -O ihex $#
# rule to create a listing file from .elf
%.lss: $(PROJECT_OUT)/$(PROJECT).elf
#$(OBJDUMP) -w -h -S -C $< > $#
# rule to create a symbol table from .elf
%.sym: $(PROJECT_OUT)/$(PROJECT).elf
#$(NM) -n $< > $#
Here's some additional lines with all_objs:
# list of all objects
ALL_OBJS = $(addprefix $(PROJECT_OUT)/, $(THUMB_OBJS) $(THUMB_CPP_OBJS) $(THUMB_AS_OBJS)
$(ARM_OBJS) $(ARM_CPP_OBJS) $(ARM_AS_OBJS))
# list of all dependency files
ALL_DFILES = $(ALL_OBJS:.o=.d)
And here's some additional lines with Project_out and project:
# where should the output files be located
PROJECT_OUT ?= $(PROJECT)_build
# default linker flags
LDFLAGS += -T $(LD_FILE) -mthumb -u _start -Wl,--gc-section -Xlinker -M -Xlinker -
Map=$(PROJECT_OUT)/$(PROJECT).map -nostartfiles -lstdc++
# default rule
all: dirs cleanhex $(PROJECT).hex $(PROJECT_OUT)/$(PROJECT).bin
$(PROJECT_OUT)/$(PROJECT).lss $(PROJECT_OUT)/$(PROJECT).sym projectinfo
# create the output directories
dirs:
#-if [ ! -e $(PROJECT_OUT) ]; then mkdir $(PROJECT_OUT); fi;
#-$(foreach DIR,$(DIRS), if [ ! -e $(PROJECT_OUT)/$(DIR) ]; \
then mkdir -p $(PROJECT_OUT)/$(DIR); fi; )
I'm pretty new to the whole Make and Makefile topic, so I'm having a hard time figuring out the problem. I appreciate every help.
You should be clear in your question what OS you're working on. It seems from the error message above you're working on Windows. The makefile you're trying to use is very clearly targeted at a UNIX system like GNU/Linux or possibly MacOS.
If you are not familiar with the differences between Windows and UNIX (which are vast and deep) you will definitely have a lot of learning to do before you can even start to get this working.
To use UNIX environments on Windows you need to use something like WSL, or Cygwin, or at least install a MinGW shell environment. When you do that you need to be using UNIX paths, not Windows paths. Windows paths use backslashes (which are escape sequences in UNIX) and drive letters (which have no equivalent in UNIX) and in makefiles in particular the : character is special to make so using paths with drive letters is a problem.
You can debug your makefile by adding $(info ...) functions to show you the value of variables:
# rule to create .elf file
$(info PROJECT_OUT = $(PROJECT_OUT))
$(info PROJECT = $(PROJECT))
$(info ALL_OBJS = $(ALL_OBJS))
$(PROJECT_OUT)/$(PROJECT).elf: $(ALL_OBJS)
#$(CC) $(CFLAGS) $(ALL_OBJS) $(LIBS) $(LDFLAGS) -o$#
I know there are other issues with similar titles, but they don't seem to hold the solution.
Heres my makefile:
# Compiler Command
CC = mpiCC
CFLAGS = -c -I./header
# collecting object file names
src = $(wildcard source/*.cpp)
src1 = $(src:.cpp=.o)
objects := $(src1:source/%=bin/%)
# Compile object files into binary
all : $(objects)
$(CC) -o run $(objects)
ifneq($(n),) // <- error location , line 15
mpirun -np $(n) run
endif
# Generate object files by compiling .cpp and .h files
bin/%.o : source/%.cpp
$(CC) $(CFLAGS) $?
mv *.o bin
# Clean Recipe
.PHONY : clean
clean :
rm -rf all $(objects)
The goal of the ifneq is to have the binary run whenever it finishes compiling.
for example, a user runs the command:
make <- builds without running
make n=5 <- builds and runs on 5 processes
Whenever I use either of these, I get the error:
makefile:15: *** missing separator. Stop.
I've used cat -e -t -v to verify everything is tabbed instead of spaced. according to (https://www.gnu.org/software/make/manual/make.html#Conditional-Example) this conditional should function.
#MadScientist solved it. You need to put a space in between ifneq and its argument. For example:
ifneq($(n),0) is invalid.
ifneq ($(n),0) is valid.
I'm updating the title and content here to make it clear that this particular question was asking something that I didn't see answered plainly elsewhere. The key notion is understanding that something that looks like a single target doing multiple things in a Makefile is actually multiple targets doing one thing each.
I will also remove some extraneous material since that ended up not being relevant.
Original Content
My problem is that I have a Makefile that is (apparently) not calling one of my sub-directory Makefiles correctly. I have a project structure like this:
quendor
src
cheap
cheap_init.c
Makefile
zmachine
main.c
Makefile
Makefile
The Makefile in the project root will refer to the Makefiles in the individual directories. Here is that core Makefile:
CC ?= gcc
CFLAGS += -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
CFLAGS += -O2 -fomit-frame-pointer
RANLIB ?= $(shell which ranlib)
AR ?= $(shell which ar)
export CC
export AR
export CFLAGS
export RANLIB
SRC_DIR = src
ZMACHINE_DIR = $(SRC_DIR)/zmachine
ZMACHINE_LIB = $(ZMACHINE_DIR)/quendor_zmachine.a
CHEAP_DIR = $(SRC_DIR)/cheap
CHEAP_LIB = $(CHEAP_DIR)/quendor_cheap.a
SUB_DIRS = $(ZMACHINE_DIR) $(CHEAP_DIR)
SUB_CLEAN = $(SUB_DIRS:%=%-clean)
$(SUB_DIRS):
#echo $(SUB_DIRS) # src/zmachine src/cheap
#echo "DIR:"
#echo $# # src/zmachine
$(MAKE) -C $#
$(SUB_CLEAN):
-$(MAKE) -C $(#:%-clean=%) clean
clean: $(SUB_CLEAN)
help:
#echo "Quendor"
.PHONY: $(SUB_DIRS) $(SUB_CLEAN) clean help
A key problem for me is this bit from the above:
$(SUB_DIRS):
#echo $(SUB_DIRS) # src/zmachine src/cheap
#echo "DIR:"
#echo $# # src/zmachine
$(MAKE) -C $#
I put the echo statements in just to show what's happening. Notice the $SUB_DIRS is correctly showing both directories, but when the Makefile runs it only shows src/zmachine. (The comments there indicate what I see during runtime.) The Makefile (apparently) doesn't process src/cheap.
The full output of the Makefile running is this (the first three lines there being my echo statements):
src/zmachine src/cheap
DIR:
src/zmachine
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C src/zmachine
cc -Wall -std=c99 -D_POSIX_C_SOURCE=200809L -O2 -fomit-frame-pointer -fPIC -fpic -o main.o -c main.c
ar rc quendor_zmachine.a main.o
/usr/bin/ranlib quendor_zmachine.a
** Done with Quendor Z-Machine.
The only thing I could think of initially was that perhaps after running the sub-makefile in src/zmachine, the Make process was either erroring out or thinking it was done. But the $(SUB_DIRS) part should have iterated through both directories, I would have thought.
So I'm a bit stuck as to how to proceed.
Extra Note: The "I would have thought" part of what I said was where I was incorrect. $(SUB_DIRS) was not being executed as I thought it was; the accepted answer has clarified this.
The way make works is, if you don't provide an argument, it will start by scanning the Makefile looking for the "default goal". The default goal is simply the first target it encounters (notice it's the first target, not targets).
In your case, the rule:
$(SUB_DIRS):
$(MAKE) -C $#
Is equivalent to:
src/zmachine src/cheap:
$(MAKE) -C $#
Which is equivalent to:
src/zmachine:
$(MAKE) -C $#
src/cheap:
$(MAKE) -C $#
So the first target make encounters is src/zmachine, and that's its default goal and the one that gets processed. The way to fix this is, as user657267 said in the comments, to add one target that you know will be processed first that would have the other targets (that you really want to build) as its prerequisites.
For a task, I've got a Makefile provided with this content:
# Flag that states that warnings will not lead to compilation errors
FORCE = false
# Compiler
CC = gcc
# Doc generator
DOC = doxygen
# Include directories
INCLUDES =
# Compiler flags
CFLAGS_FORCE = -c -g -ansi -pedantic -Wall -Wextra
CFLAGS = $(CFLAGS_FORCE) -Werror
# Linker flags
LDFLAGS =
# Source codes
SOURCE = ueb01.c
OBJECTS = $(SOURCE:.c=.o)
# Target name
BINARY = ueb01
.PHONY: all help clean doc doc
default: all
force:
#make FORCE=true
all: $(BINARY)
# Compile a single file
%.o : %.c
#echo " - Building $#"
ifeq ($(FORCE),true)
$(CC) $(CFLAGS_FORCE) $(INCLUDES) -o $# $<
else
$(CC) $(CFLAGS) $(INCLUDES) -o $# $<
endif
#echo " ... done"
# Link files to an executable
$(BINARY): $(OBJECTS)
#echo " - linking $#"
$(CC) $(LDFLAGS) $(OBJECTS) -o $(BINARY)
#echo " ... done"
# Clean the project
clean:
#echo " - delete object all files"
rm -f $(OBJECTS) $(BINARY) *~ doxygen.log
rm -rf doc/
#echo " ... done"
doc:
#echo " - creating documentation"
$(DOC)
#echo " ... done"
# Show help
help:
#echo "Options:"
#echo "make all - create program"
#echo "make clean - clean up"
#echo "make doc - create documentation"
#echo "make force - compile without -Werror (just for 'comfier' development)"
Within same folder as the Makefile, I've got a program.c file that I'd like to execute. The content of that file is not relevant here, because I can't even compile the .c file with the provided Makefile. So when I'm the cmd window and type in make or make all, following lines are being displayed:
MAKE Version 5.4 Copyright (c) 1987, 2010 Embarcadero Technologies, Inc.
Error makefile 45: Command syntax error
Error makefile 46: Command syntax error
Error makefile 47: Command syntax error
Error makefile 48: Command syntax error
Error makefile 49: Command syntax error
Error makefile 50: Command syntax error
*** 6 errors during make ***
The Makefile was provided by my supervisors for the task and works fine as it's supposed to do for my friends but strangely not for me.
I've tried to solve this by installing CMake by Kitware but it gives me the same errors.
I'm running on Windows 10 (64 Bit).
Thanks in advance! T.T
I am getting make file error on line 139 below at $(eval $(RULES))
I am really inexperienced in make file syntax.
This is is error it is giving me when I enter make command.
common.mak:139: *** missing separator. Stop.
I tried to removed the tab by single space, \t nothing works.
Do you know what can be the reason?
Thanks
#
# common bits used by all libraries
#
# first so "all" becomes default target
all: all-yes
ifndef SUBDIR
ifndef V
Q = #
ECHO = printf "$(1)\t%s\n" $(2)
BRIEF = CC CXX HOSTCC HOSTLD AS YASM AR LD STRIP CP
SILENT = DEPCC DEPHOSTCC DEPAS DEPYASM RANLIB RM
MSG = $#
M = #$(call ECHO,$(TAG),$#);
$(foreach VAR,$(BRIEF), \
$(eval override $(VAR) = #$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
$(foreach VAR,$(SILENT),$(eval override $(VAR) = #$($(VAR))))
$(eval INSTALL = #$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
endif
ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample
# NASM requires -I path terminated with /
IFLAGS := -I. -I$(SRC_PATH)/
CPPFLAGS := $(IFLAGS) $(CPPFLAGS)
CFLAGS += $(ECFLAGS)
CCFLAGS = $(CPPFLAGS) $(CFLAGS)
ASFLAGS := $(CPPFLAGS) $(ASFLAGS)
CXXFLAGS += $(CPPFLAGS) $(CFLAGS)
YASMFLAGS += $(IFLAGS:%=%/) -Pconfig.asm
HOSTCCFLAGS = $(IFLAGS) $(HOSTCPPFLAGS) $(HOSTCFLAGS)
LDFLAGS := $(ALLFFLIBS:%=$(LD_PATH)lib%) $(LDFLAGS)
define COMPILE
$(call $(1)DEP,$(1))
$($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $<
endef
COMPILE_C = $(call COMPILE,CC)
COMPILE_CXX = $(call COMPILE,CXX)
COMPILE_S = $(call COMPILE,AS)
%.o: %.c
$(COMPILE_C)
%.o: %.cpp
$(COMPILE_CXX)
%.s: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -S -o $# $<
%.o: %.S
$(COMPILE_S)
%.i: %.c
$(CC) $(CCFLAGS) $(CC_E) $<
%.h.c:
$(Q)echo '#include "$*.h"' >$#
%.ver: %.v
$(Q)sed 's/$$MAJOR/$($(basename $(#F))_VERSION_MAJOR)/' $^ > $#
%.c %.h: TAG = GEN
# Dummy rule to stop make trying to rebuild removed or renamed headers
%.h:
#:
# Disable suffix rules. Most of the builtin rules are suffix rules,
# so this saves some time on slow systems.
.SUFFIXES:
# Do not delete intermediate files from chains of implicit rules
$(OBJS):
endif
include $(SRC_PATH)/arch.mak
OBJS += $(OBJS-yes)
FFLIBS := $(FFLIBS-yes) $(FFLIBS)
TESTPROGS += $(TESTPROGS-yes)
LDLIBS = $(FFLIBS:%=%$(BUILDSUF))
FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(EXTRALIBS)
EXAMPLES := $(EXAMPLES:%=$(SUBDIR)%-example$(EXESUF))
OBJS := $(sort $(OBJS:%=$(SUBDIR)%))
TESTOBJS := $(TESTOBJS:%=$(SUBDIR)%) $(TESTPROGS:%=$(SUBDIR)%-test.o)
TESTPROGS := $(TESTPROGS:%=$(SUBDIR)%-test$(EXESUF))
HOSTOBJS := $(HOSTPROGS:%=$(SUBDIR)%.o)
HOSTPROGS := $(HOSTPROGS:%=$(SUBDIR)%$(HOSTEXESUF))
TOOLS += $(TOOLS-yes)
TOOLOBJS := $(TOOLS:%=tools/%.o)
TOOLS := $(TOOLS:%=tools/%$(EXESUF))
HEADERS += $(HEADERS-yes)
DEP_LIBS := $(foreach NAME,$(FFLIBS),lib$(NAME)/$($(CONFIG_SHARED:yes=S)LIBNAME))
SRC_DIR := $(SRC_PATH)/lib$(NAME)
ALLHEADERS := $(subst $(SRC_DIR)/,$(SUBDIR),$(wildcard $(SRC_DIR)/*.h $(SRC_DIR)/$(ARCH)/*.h))
SKIPHEADERS += $(ARCH_HEADERS:%=$(ARCH)/%) $(SKIPHEADERS-)
SKIPHEADERS := $(SKIPHEADERS:%=$(SUBDIR)%)
HOBJS = $(filter-out $(SKIPHEADERS:.h=.h.o),$(ALLHEADERS:.h=.h.o))
checkheaders: $(HOBJS)
.SECONDARY: $(HOBJS:.o=.c)
alltools: $(TOOLS)
$(HOSTOBJS): %.o: %.c
$(call COMPILE,HOSTCC)
$(HOSTPROGS): %$(HOSTEXESUF): %.o
$(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $< $(HOSTLIBS)
$(OBJS): | $(sort $(dir $(OBJS)))
$(HOBJS): | $(sort $(dir $(HOBJS)))
$(HOSTOBJS): | $(sort $(dir $(HOSTOBJS)))
$(TESTOBJS): | $(sort $(dir $(TESTOBJS)))
$(TOOLOBJS): | tools
OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(TESTOBJS))
CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.ho *.gcno *.gcda
DISTCLEANSUFFIXES = *.pc
LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
define RULES
clean::
$(RM) $(OBJS) $(OBJS:.o=.d)
$(RM) $(HOSTPROGS)
$(RM) $(TOOLS)
endef
$(eval $(RULES))
-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d))
I experienced that same issue when trying to configure ffmpeg for make.
With the current version of ffmpeg's master branch the issue occurs for common.mak at line 160.
To solve this issue I tried the following steps:
git config core.autocrlf false
delete all *.mak files
git reset --hard
These steps alone did not fully solve my problem. Based on the hints regarding the TAB (\t) characters I changed line 160 from
to
Note the arrow (indicating a TAB) at line 160 between $( and eval $(RULES)).
This TAB solved the problem for me. I had to make this change to a further *.mak file. There was the same error message for another file. By the way, Notepad++ is a great tool to insert a TAB as well as for changing the line endings.
Since ffmpeg takes a while for building I decided to share my solution...
I had this exact same issue - when also checking out FFMPEG on Windows but using git.
After running configure and when trying to run make I got the same line:
common.mak:139: *** missing separator. Stop.
As suggested by #MadScientist - Makefiles are particularly fussy not just about tab (\t) but also the choice of line ending (LF vs. CRLF).
This is down to the GNU make command which has to run them - which seems to only respect LF.
So a *nix version, such as this, will work:
And here is the same file under Windows, which won't work:
(Another giveaway is that it is also bigger with double the bytes at the end of each line!)
Bottom line (so to speak) is that you might have to reformat your files - perhaps by using the dos2unix command.
This would still be the case even if not directly cloning from git - but instead downloading a tar/zip that was itself created from a git clone. The end of lines would be preserved.
Or, if using Git (directly as I was) you have to tell it how to handle the end of line characters. When it checks-out/clones and when it commits.
There is a full description of what this means here: http://adaptivepatchwork.com/2012/03/01/mind-the-end-of-your-line/
And how it can be configured (for the old version of git) via the [core].eol setting.
This is also apparent on Windows, when if you run the installer (e.g. http://git-scm.com/downloads) you get a dialogue such as this:
Selecting the final option to "checkout as-is, commit as-is" fixed it for me. Not perhaps the most principled way, but it forced the LF endings to be preserved.
In makefiles, recipe lines MUST start with a TAB character (TAB must be the first character on the line). You cannot have one or more spaces at the beginning of the line, either with or without a following TAB.
I don't know what you mean by: I tried to removed the tab by single space, \t nothing works; that sentence doesn't make sense to me. Hopefully the above paragraph will help you understand what you need to do.
Be sure you're using a text editor (not a word processor) and that your editor doesn't try to "helpfully" change the formatting in your files.
In general, unless you're more experienced with makefiles I don't recommend using the eval function, which requires a pretty clear understanding of the rules make uses for expanding variables and functions to use correctly. I'm not really sure why you're using eval in the context of the RULES variable, anyway; why not just write the rule directly without eval?