Script to compile C code - c

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.

Related

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.

using MAKEFILE to copy files before compilation and delete them after

I am trying to copy files befoe compilation (I have two source files with same name so I copy the files to a files with a different name) and delete them at the end of the MAKEFILE.
I am trying to do the folliwng but probably there is mismatch in the execution order.
How can I do it correctly?
all: copy_dup_files $(dst_dir) $(APP_TARGET_LIB) delete_dup_files
copy_dup_files:
#echo "COPYING DUP FILES"
$(shell cp /aaa/hmac.c /aaa/hmac1.c )
$(shell cp /bbb/hmac.c /bbb/hmac2.c )
delete_dup_files:
#echo "DELETING DUP FILES"
$(shell rm /aaa/hmac1.c )
$(shell rm /bbb/hmac2.c )
Thanks
The purpose of $(shell) is to produce an output which Make reads. The recipe lines should not have this construct at all.
# this is evaluated when the Makefile is read
value := $(shell echo "Use the shell to produce a value for a variable")
# this is evaluated when you say "make foo"
foo:
echo 'No $$(shell ...) stuff here'
So, all the $(shell ...) stuff in your attempt gets evaluated when the Makefile is read, but before any actual target is executed.
Your makefile is trying to say /aaa/hmac1.c depends on /aaa/hmac.c.
Thus we have:
/aaa/hmac1.c: /aaa/hmac.c
cp $< $#
/bbb/hmac2.c: /bbb/hmac.c
cp $< $#
/aaa/hmac1.o /bbb/hmac2.o: %.o: %.c
gcc $< -o $#
myprog: /aaa/hmac1.o /bbb/hmac2.o
gcc $^ -o $#
This is clean and parallel safe (a good test of any makefile).
There are innumerable style improvements you could make, like
Get rid of the absolute paths
Use symbolic links instead of copying
Automatic dependency generation (for .h files, etc.)
Don't besmirch the source tree — put all the intermediate files (the .os and the temporary .cs) in their own build folder
&c. &c.

How to modify makefile to compile changed source into object directory except for a list of files

I inherited a makefile that uses GNU Make 3.81. It is overly complicated, IMHO because it does not use patterns. In addition, it does not automatically create an object file directory when needed. I've looked at several examples and read the a GNU makefile manual, but still not seeing something that should be simple. There seem to be many ways recommended, but not clear what to use. I have about 60 c files that need to be compiled into a directory named obj. But, I don't want 6 test programs that have 'main' programs compiled into that directory. They are in a list called OTHERSRCS. I'd like to have the c files less the OTHERSRCS compiled into obj if anything changes in those files. Also, if the obj directory doesn't exist, I'd like to create it. The 'make clean' should remove that directory. I've used ANT with Java and can get the dependencies to work, but I'm not succeeding with this makefile. A simple example would be helpful that used some sort of exclusion along with the pattern for the c files.
In this simple example, the C source files in the current directory
are foo.c, bar.c, atest.c, anothertest.c. We have:
OTHERSRCS := atest.c anothertest.c
Each of the $(OTHERSRCS) is to be separatedly compiled and linked into
a program in current directory. All remaining C source files, whatever
the are, are to be compiled into a directory obj, which shall be
created when required, and the resulting object files all linked into
a program foobar.
Makefile
ALLSRCS := $(wildcard *.c)
OTHERSRCS := atest.c anothertest.c
foobar_SRCS := $(filter-out $(OTHERSRCS),$(ALLSRCS))
foobar_OBJS := $(addprefix obj/,$(foobar_SRCS:.c=.o))
PROGS := foobar atest anothertest
.PHONY: all clean
all : $(PROGS)
obj/%.o: %.c | obj
$(COMPILE.c) $< -o $#
obj:
mkdir -p $#
foobar: $(foobar_OBJS)
$(LINK.o) -o $# $^ $(LDLIBS)
clean:
rm -fr $(PROGS) obj
The default make runs like:
$ make
mkdir -p obj
cc -c foobar.c -o obj/foobar.o
cc -c foo.c -o obj/foo.o
cc -c bar.c -o obj/bar.o
cc -o foobar obj/foobar.o obj/foo.o obj/bar.o
cc atest.c -o atest
cc anothertest.c -o anothertest
and of course make foobar like the first 5 lines of that.
To understand the key details, see 4.3 Types of Prerequisites
and 8.2 Functions for String Substitution and Analysis
in the manual. No recipes need be written for the programs atest and anothertest in this example because they're correctly built by GNU make's default rules.
If you are going to rework your inherited makefile, consider rationalising the source tree, e.g. by at least not having test sources in the same directory as application sources.
Here's my Makefile
This should get you going. I tried to be as descriptive as I could.
Edit:
To exclude a .c file you can change:
SRC = $(shell find $(SRC_DIR) -name '*.c')
to
SRC = $(shell find $(SRC_DIR) -name '*.c' ! -iname 'myFile.c')

Makefile for C Program

I am trying to use this Makefile for a C Program. Could you please share with me a way how I can understand the Make utility better? I am trying the following:
# stack/Makefile
CC := gcc
CFLAGS += -std=c99
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -g
VPATH = main src
all: bin/main.exe clean run
bin/main.exe: bin/main.o bin/stack.o
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
bin/main.o: main.c
bin/stack.o: stack.c stack.h
bin/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
demo:
../bin/main.exe
clean:
rm -f bin/*.o
run:
bin/main.exe
.PHONY: all clean run
And I getting this message:
gcc -std=c99 -Wall -Wextra -g -c -o bin/main.o main.c
error: unable to open output file 'bin/main.o': 'No such file or directory'
1 error generated.
make: *** [bin/main.o] Error 1
The error stems from the fact that your Makefile wants to
generate the executable and object files in subdirectory bin but it
contains no rule to ensure that bin exists when it is
needed. As #JonathanLeffler comments, you can solve that
just by manually creating bin yourself.
But it is often desired that a Makefile itself will ensure
that a subdirectory, or some other resource, exists when it
is needed, and you probably assumed that the pattern-rule
bin/%.o: %.c
would create bin as needed. It won't.
Your Makefile can ensure the existence of bin if you
amend it like this:
Somewhere below the all rule, add a new target:
bin:
mkdir -p $#
This is to make the bin subdirectory if it doesn't exist.
Then change the rule:
bin/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
to:
bin/%.o: %.c | bin
$(CC) $(CFLAGS) -c -o $# $<
The additional | bin is an example of an order-only prequisite
It means: If any of the targets (the bin/%.o things) needs to be remade from any of preceding prequisites (the ones before |, i.e. the %.c
things), then bin must be made first. So, as soon as anything needs to be made in bin, bin will be made first.
There is another more basic flaw in your Makefile. all is dependent on clean, so every time you successfully build
your program the object files are deleted. I understand that you intend this, but it entirely
defeats the purpose of make, which is to avoid the need to rebuild everything (object files, executables) every
time by instead just rebuilding those things that have become out-of-date with respect to their prerequisites.
So all should not depend on clean, and then an object file will be recompiled only if it needs to
be recompiled, i.e. is older than the corresponding source file. If and when you want to clean out the
object files, run make clean.
Finally, your demo rule:
demo:
../bin/main.exe
is inconsistent with the others. The others assume that the bin where the executable
is put is in the current directory. The demo rule assumes it is in the parent of
the current directory. If you correct the demo rule then it will be identical to
the run rule, so it is superfluous, but if it were not superfluous then it should
be added it to the .PHONY targets.
The best way to learn the proper way to use makefiles is to read the manual. Also, you can Google for some simple tutorials.

Why does this makefile not apply includes to all objects?

This makefile does not behave as I expect. I want it to build .o files for each .c file in the current directory and subdirectories, and put them in a static library. However, it stops applying my $(INCS) after the first or second file. When it tries to build the second .o file, I don't see the -I paths in the build line and it complains about not finding a header file therein. Names have been genericized to simplify things. I'm using cygwin on Windows XP. I'm using an ARM cross compiler that is not under the cygwin tree. I based this makefile off an answer here. There are only about two dozen .c files so the overhead of creating the dependency files this way isn't a big deal.
# Project specific options
CC = my-cross-gcc
INCS := -I. -Iinc
INCS += -Imy/inc/path
CFLAGS := -Wall -fPIC -static -cross-compiler-specific-options
OUT := bin/libmylib.a
MKDIR:=mkdir -p
### Generic C makefile items below:
# Add .d to Make's recognized suffixes.
SUFFIXES += .d
NODEPS:=clean
#Find all the C files in this directory, recursively
SOURCES:=$(shell find . -name "*.c")
#These are the dependency files
DEPFILES:=$(patsubst %.c,%.d,$(SOURCES))
OBJS:= $(patsubst %.c,%.o,$(SOURCES))
#Don't create dependencies when we're cleaning, for instance
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
-include $(DEPFILES)
endif
#This is the rule for creating the dependency files
%.d: %.c
$(CC) $(INCS) $(CFLAGS) -MM -MT '$(patsubst %.c, %.o,$(patsubst %.c,%.o,$<))' $< > $#
#This rule does the compilation
%.o: %.c %.d %.h
$(CC) $(INCS) $(CFLAGS) -o $# -c $<
# Now create a static library
all: $(OBJS)
#$(MKDIR) bin
ar rcsvq $(OUT) $(OBJS)
clean:
rm -rf $(OBJS) $(OUT) $(DEPFILES)
Why does this makefile not apply $(INCS) when building subsequent .o files? How do I fix it? Output resembles this:
$ make all
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o firstfile.o -c firstfile.c
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o secondfile.o -c secondfile.c
my-cross-gcc -<compiler flags> -o thirdfile.o -c thirdfile.c
thirdfile.c:23:18: fatal error: myinc.h: No such file or directory
compilation terminated.
When I go to the command line and type in the gcc line to build thirdfile.o and use the -I paths, the object file is successfully built.
There are two different mechanisms for handling header files at work here:
When the compiler is trying to build foo.o from foo.c, and in foo.c it encounters #include "foo.h", it goes looking for foo.h. The -I flags tell it where to look. If it is invoked without the flags it needs to find foo.h, it will complain and die.
When Make is trying to build foo.o, and considering which rule to use, it looks at the prerequisites. The prerequisites for your rule are foo.c foo.d foo.h, so it goes looking for those prerequisites. How is it to know where foo.h is? Note that the compiler flag inside one of its commands is of no use-- it won't make any deductions about that. If it can't find (and doesn't know how to make) a prerequisite, it will reject that rule and look for another one, such as the implicit %.o rule which knows nothing about your $(INCS) variable, and that leads you to the problem described above.
If this is the problem (and you can check by looking at the locations of the headers and doing some experiments) you have a couple of options:
A) You can use the implicit rule, and it's variables. Just add INCS to CFLAGS and you'll probably get the results you want. This tells the compiler what to do, but it still leaves Make in the dark about the dependencies, so you'll probably have to double-check that your dependency handling is correct.
B) You can tell Make where to find the header files:
vpath %.h inc my/inc/path
(You may notice that this is redundant with your INCS variable, and redundancy is bad-- you can eliminate this redundancy, but I urge you to get it working first.)
I'm going to guess that you have files named firstfile.h, secondfile.h, but no file named thirdfile.h?
I would then suppose that make cannot use the rule you gave it because and can't find or build the .h file. So it decides to use the default implicit rule instead.
All I can imagine is that for "thirdfile" your depfile is somehow out-of-date or corrupt. Perhaps it is bad enough that it's confusing make into calling some other default target.

Resources