I'm trying to write a command which builds either a file that I pass as a flag, or all files.
I have this for now:
SOURCES := $(shell find ./src -name '*.c')
FILE?="all"
# Compile source files into object files
compile:
ifeq ($(FILE), "all")
for file_dir in $(SOURCES); do \
$(CC) $(CFLAGS) -o $($$file_dir:.c=.o) -c $$file_dir \
done;
else
$(CC) $(CFLAGS) -o ./out/$(FILE).o -c ./src/$(FILE).c
endif
But since I've added the loop, I get this error:
$ make compile
for file_dir in ./src/board.c ./src/main.c; do \
gcc "-Wall" -o -c $file_dir \
done;
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [compile] Error 2
I agree with the comments above: this is a bad way to write a makefile. If you just want to compile every file every time, write a shell script.
But, to explain the error you see:
You have your semicolon in the wrong place:
for file_dir in $(SOURCES); do \
$(CC) $(CFLAGS) -o $($$file_dir:.c=.o) -c $$file_dir \
done;
The semicolon needs to be after the compile command, not after the done. Without a semicolon after the compile command, the done keyword is used as an argument to the compiler and then there is no done keyword, leading to the shell syntax error you see.
for file_dir in $(SOURCES); do \
$(CC) $(CFLAGS) -o $($$file_dir:.c=.o) -c $$file_dir; \
done
ETA
Also, this is wrong: $($$file_dir:.c=.o) You are trying to use a make variable expansion on a shell variable. That cannot work: all make variables are expanded BEFORE the shell is invoked.
You need something like $${file_dir%.c}.o, using shell features.
PPS
All your makefile appears to do is compile the files. Make has built-in rules that know how to do this. All you have to do is this:
SOURCES := $(shell find ./src -name '*.c')
compile: $(SOURCES:.c=.o)
That's it. Make knows how to compile a .c file and create a .o file, on its own.
Related
Here are parts of a Makefile:
MY_SRC += \
scr1.c \
src2.c \
src3.c
BUILD_PATH=outdir
MY_OBJ := $(addprefix $(BUILD_PATH)/,$(addsuffix .o, $(MY_SRC)))
MY_DEP := $(MY_OBJ:.c.o=.c.d)
.
.
.
$(BUILD_PATH)/%.c.o: %.c
#echo " CC $<"
$(CC) $< -c $(CFLAGS) $(call MDOPT,$(#:.c.o=.c.d)) -o $#
.
.
.
-include $(MY_DEP)
The MDOPT is defined as MDOPT = -MMD -MF $(1).
I needed to add assembly .asm.ssource files, so I added:
MY_SRC += myfile.asm.s
.
.
.
$(BUILD_PATH)/%.s.o: %.s
#echo " ASM $<"
$(Q)$(CC) $< -c $(CFLAGS) -o $#
However, when trying to compile the sources, it gave me error:
ASM myfile.asm.s out/myfile.asm.s.o:1: *** missing separator. Stop.
I have found the following fix - remove the last line in the Makefile:
-include $(MY_DEP).
What caused the error?
Why did removal of the -include line fix the problem? What is the purpose of this line at all?
What caused the error?
The error message suggests a syntax error in the binary file
out/myfile.asm.s.o. The error isn't detected at include time because
the -include directive was used (try info make include, near the
end). myfile.asm.s is appended to MY_SRC, and out/myfile.asm.s.o
therefore to MY_OBJ and MY_DEP. The binary file gets included
because MY_DEP := $(MY_OBJ:.c.o=.c.d) leaves .s.o intact.
UPDATE: To be more precise about the timeline,
make, on seeing -include $(MY_DEP), decides it can remake the
requested .s.so file from an implicit rule; no errors at this
point, even if it could not be remade
builds the .s.so displaying the output from #echo but not the
$(CC) command line (since $(Q) expands to #, it seems); no errors yet
reads and parses the .s.so as a makefile, fails on line 1, and
terminates with an error message (end UPDATE)
Why did removal of the -include line fix the problem?
It skips reading out/myfile.asm.s.o which isn't a makefile.
What is the purpose of this line at all?
See info make 'Automatic Prerequisites'.
The problem was resolved in two steps:
MY_DEP := $(MY_OBJ:.c.o=.c.d) did not take in the .s assembly files. This was fixed with:
MY_DEP_TEMP := $(MY_OBJ:.c.o=.c.d)
MY_DEP += $(MY_DEP_TEMP:.s.o=.s.d)
Additional target for compiling .s files needed to be changed in order to generate .d files:
$(BUILD_PATH)/%.s.o: %.s
#echo " AS $<"
$(AS) $< -c $(ASFLAGS) $(call MDOPT_ASM,$(#:.s.o=.s.d)) -o $#
Special care needed to be taken with respect to MDOPT_ASM which needed to be defined as MDOPT_AS = -MD $(1), which is different then the one for .c targets (MDOPT_C = -MMD -MF $(1)).
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.
Usually if I want to compile a C program called number_input.c I would type
cc -o number_input number_input.c
I want to use my mac terminal to make a script so that I don't have to type that extra word. Originally I did this to save myself 1 sec of programming but ironically I've spent over 2 hrs trying to get this to work.
a= echo "$1" | rev | cut -c3- | rev
echo $a
cc -o $a $1
echo $1
This is my output:
number_input
clang: error: no input files
number_input.c
I can tell that the names are being inputted correctly but for some reason the cc command isn't taking in the value of $1? I am assuming that somehow the $1 isn't directly converted into a string or something like that but I am not sure.
Your error is on the first line, since you're not assigning anything to a:
a=$(echo "$1" | rev | cut -c3- | rev)
Would fix the problem (for well-behaved filenames, at least, since you're missing quotes further down in your script). A space after a means you're assigning an empty string to it and then running the commands in the pipeline.
Instead of going to all the effort of reversing the twice, just remove the last two characters with ${1%??}:
cc -o "${1%??}" "$1"
The most common tool to do this is make. It reads the recipes from a file named Makefile in the directory it is run, and performs any tasks necessary. It is smart enough to check the file timestamps to detect if or which parts of your projects need to be re-compiled. Here is an example Makefile:
CC := gcc
CFLAGS := -Wall -O2
LDFLAGS := -lm
PROGS := number_input
.PHONY: all clean
all: $(PROGS)
clean:
rm -f $(PROGS)
$(PROGS): %: %.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
Note that indentation in a Makefile must use tabs, not spaces. If you copy the above, and paste to a file, you will need to run sed -e 's|^ *|\t|' -i Makefile to fix the indentation.
The first three lines name the compiler used, the compiler options, and the linking options. The -lm linking option is not needed for your particular use case; I just included it because you will sooner or later want to use <math.h>, and then you do need to include the -lm linking option.
The PROGS line names your programs. You can specify more than one, just separate them by spaces.
The .PHONY: line tells make that targets all and clean are "phony", that they do not generate files of that name.
The all recipe, as the first recipe in a Makefile, is the default recipe that is followed, when you run make. This one tells that all programs listed in PROGS should be built.
The clean recipe (run make clean) removes all temporary files and compiled files from the directory -- essentially cleaning it.
The last recipe is a tricky one. It says that all the files listed in PROGS are each built from a file having the same name plus a .c suffix. The $^ refers to the .c file name, and $# to the file name without the suffix.
If this Makefile were used for returning exercises via email to a teacher, I'd also add a new .PHONY target, tarball:
CC := gcc
CFLAGS := -Wall -O2
LDFLAGS := -lm
PROGS := number_input
TAR := $(notdir $(CURDIR)).tar
.PHONY: all clean tarball
all: $(PROGS)
clean:
rm -f $(PROGS)
tarball: clean
rm -f ../$(TAR)
tar -cf ../$(TAR) $(notdir $(CURDIR))/
$(PROGS): %: %.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
Running make will compile number_input, if number_input.c has been modified after the last time number_input was compiled, or if number_input does not exist yet.
Running make TAR=myname-ex01.tar tarball removes the compiled files from the current directory, then creates a tarball of the current directory (and its subdirectories, if any) in the parent directory as myname-ex01.tar. If you run just make tarball, the tar file name will be the same as the name of the current directory, but with a .tar suffix.
I hope you can see why writing a Makefile is so useful.
#compile time flags
CFLAGS=-Wall -Werror
CC=gcc
all: prog-1-gcc prog-2-gcc prog-3-gcc prog-4-gcc prog-5-gcc prog-6-gcc \
prog-7-gcc prog-8-gcc prog-9-gcc prog-10-gcc prog-11-gcc prog-12-gcc \
prog-13-gcc prog-14-gcc prog-15-gcc prog-16-gcc prog-17-gcc prog-18-gcc \
prog-19-gcc prog-20-gcc prog-21-gcc
all-gcc: all
run: run-1-gcc run-2-gcc run-3-gcc run-4-gcc run-5-gcc run-6-gcc \
run-7-gcc run-8-gcc run-9-gcc run-10-gcc run-11-gcc \
run-12-gcc run-13-gcc run-14-gcc run-15-gcc run-16-gcc \
run-17-gcc run-18-gcc run-19-gcc run-20-gcc run-21-gcc
run-gcc: run
prog-%-gcc: prog-%.c
$(CC) $(CFLAGS) $< -o prog-$*.out
run-%-gcc: prog-%.out
-./prog-$*.out
make clean:
rm -f all *.out
This makefile gives me this error on solaris9 machine when i type
bash-2.05$ make prog-9-gcc
make: Fatal error: Don't know how to make target `prog-9-gcc'
This happens with all rules including the make clean rule. I would appreciate anyone's input as i have been stuck with this bug for a few days now thanks!I should also probably mention this makefile runs 100% perfectly on a centos machine.
Question: What can i do to my make file or my input line on solaris to make this work when compiling and running my C Files.
Answered Below in the comments by Charlie Burns
This rule tells make it can build prog-9-gcc from a file prog-9.c. So, if make is giving that error it means that there's no file proc-9.c in your directory:
prog-%-gcc: prog-%.c
gcc $(CFLAGS) prog-$*.c -o prog-$*.out
The other problem with this rule is that it tells make it will build a file prog-%-gcc (for some value of %) but it's lying. It actually builds a totally different file, prog-%.out. Because of this, make will rebuild all the targets every time you run make. This rule should read:
prog-%-gcc: prog-%.c
gcc $(CFLAGS) $< -o $#
Really you should set CC = gcc and use $(CC) in the rule.
I am modifying an old makefile in order to build a C extension for postgreSQL. The Makefile currently looks like this:
PGLIB = /usr/lib/postgresql/8.4/lib
PQINC = /usr/include/postgresql/8.4/server
CC=gcc
override CFLAGS+= $(CFLAGS_SL) -DPG_AGGREGATE
SHLIB = pg_myextlib
SRC = foo.c \
foobar.c
OBJS = foo.o \
foobar.o
all: $(OBJS)
$(CC) -shared -o $(SHLIB)$(DLSUFFIX) $(OBJS) -I$(PQINC)
cp *.so $(PGLIB)
clean:
rm -f $(SHLIB) $(OBJS)
The error I get when I run make is:
common.h:58:22: error: postgres.h: No such file or directory
Which suggests that the include path is not being added (the file exists in $PQINC).
Its a long time since I wrote the Makefile - and I haven't written many since. As an aside, I am pretty sure that 'shared' is not the gcc flag to build shared libs on Ubuntu (my current dev box) - I think the flag should be 'fPIC' - can someone confirm this?
I am runing gcc v4.4.3 on Ubuntu 10.0.4 and compiling for use with PG 8.4
Try moving the -I$(PQINC) from target all to the end of line that starts with override CFLAGS.
Placing -Isomething on the compiler line which turns object files, like those in $(OBJS), into executable will have no effect whatsoever.
You need to do it when you compile the source files.
Since your makefile doesn't explicitly show the rule for processing source files, it may well be using a default one, which is incredibly unlikely to know about PQINC.
You seem to be using the default rules to build foo.o from foo.c, which doesn't have your -I. Try adding the following rule to your Makefile:
.c.o:
$(CC) $(CFLAGS) -c $< -o $# -I$(PQINC)