My directory structure is /home/akshayaj/Desktop/System Programs/dictionary/
Inside dictionary I have 3 files:
libdictionary.c (implements all the functions except main),
libentrypoint.c (contains main()),
libdictionary.h (contains declaration of all the functions)
Both C files include the header file
Now I wrote a make file for the above project. It goes like this:-
CFLAGS=-I /home/akshayaj/Desktop/System Programs/dictionary/
libdict: libentrypoint.o libdictionary.o
cc $(CFLAGS) -o libdict libentrypoint.o libdictionary.o
libentrypoint.o: libentrypoint.c libdictionary.h
cc $(CFLAGS) -c libentrypoint.c
libdictionary.o: libdictionary.c libdictionary.h
cc $(CFLAGS) -c libdictionary.c
Now when I ran it, I got these errors:-
cc -I /home/akshayaj/Desktop/System Programs/dictionary/ -c libentrypoint.c
cc: error: Programs/dictionary/: No such file or directory
make: *** [libentrypoint.o] Error 1
Where am I going wrong?
Note:- In CFLAGS I have given the whole path because I saw it in a similar question, but that didn't work. Here is the link to that question.
C Compile Error (No such file or directory, compilation terminated)
Try to use path /home/akshayaj/Desktop/System\ Programs/dictionary/, where \ handles the space.
Think about how that command line would be parsed...
cc -I /home/akshayaj/Desktop/System Programs/dictionary/ -c libentrypoint.c
^^ ^------------------------------^ ^------------------^ ^-----------------^
| | | |
Command -I arg BAD ARG -c arg
As you can see, the space between "System" and "Programs" is read as a separator between two command args.
Your options are either:
Change the path so that the space is removed (recommended). e.g. /home/akshayaj/Desktop/System-Programs/dictionary/.
Add a backslash before the space to escape it. e.g.:
/home/akshayaj/Desktop/System\ Programs/dictionary/
As a general rule, it's not wise to use paths with spaces in them when building stuff using make, or just building stuff in general. It makes ambiguities like this hard to solve.
Related
I am customizing my Makefile for a school project.
I would like to print the following sentence but only when the .c files from my SRCS_DIR have been actually compiled.
All the .c files have been compiled successfully !
If I move the printf that you see in line 3 of the code block below to the last line, it prints the message after each .c file being compiled...
Thus, I created a COMPILED variable which I set to 0 at the beginning of my Makefile, and then I change its value to 1 during compilation (line 11 in the code block below). I tried to use the ifeq condition (line 2 in the code block below), but the sentence does not print when I do that.
$(NAME): $(LIBFT_AR) $(OBJS)
ifeq ($(COMPILED), 1)
printf "$(GREEN)> All the .c files have been compiled successfully !$(END)\n"
endif
printf "$(BLUE)> Creating the executable file :$(END) $#\n"
$(CC) $(OBJS) $(LIBFT_AR) -lreadline -o $(NAME)
printf "$(GREEN)> Executable file has been created successfully !$(END)\n"
$(OBJS_DIR):
mkdir -p $(addprefix $(OBJS_DIR)/, $(SUBDIRS_LST))
$(OBJS_DIR)/%.o: $(SRCS_DIR)/%.c $(INCS) Makefile | $(OBJS_DIR)
override COMPILED=1
$(CC) $(CFLAGS) -I $(INCS_DIR) -c $< -o $#
printf "$(BLUE)> Compiling :$(END) $<\n"
Do you have any explanation regarding this issue and/or a solution that could help me to solve the problem ?
Thank you !
Makefiles are not scripting languages. Make doesn't read the makefile and run each rule as it's read. Make will (1) parse the entire makefile (and any included files) and build an internal graph of all the prerequisites, than (2) run recipes for targets that are outdated. Content that is NOT IN A RECIPE is always evaluated during the first step. Content that IS IN A RECIPE is always evaluated during the second step.
Lines that are not indented with TABs, are not in recipes (and so are evaluated during the first step). Lines that are indented with TABs, are in recipes (and so are evaluated--which means, given to the shell to execute--during the second step).
Maybe you can now see why your attempts cannot work: the if-statements and variable assignment of COMPILED are always evaluated, during the first step, before make has decided whether or not any targets should be built.
I'm not really sure I understand your goal. If the recipe of your executable is being invoked then it means that all your source files have been compiled: that's what a makefile does. Maybe you are trying to make a distinction between a build where at least one source file was compiled, and a build where no source files had to be recompiled but the target (the executable) was out of date?
If that's what you want the simple way to solve your problem is with automatic variables; for example the $? automatic variable expands to the list of prerequisites that were out of date. You can do something like:
$(NAME): $(LIBFT_AR) $(OBJS)
test -z '$(filter %.o,$?)' || printf "$(GREEN)> All the .c files have been compiled successfully !$(END)\n"
printf "$(BLUE)> Creating the executable file :$(END) $#\n"
$(CC) $(OBJS) $(LIBFT_AR) -lreadline -o $(NAME)
printf "$(GREEN)> Executable file has been created successfully !$(END)\n"
The $(filter ...) function will expand to the list of .o files in the $? variable; if that's empty then no .o files were rebuilt.
I'm trying to include Eclipse Mosquitto library sample mosquitto example from here
I'm trying to use a Makefile to build and compile the code.
I'm facing an issue where the compiler/linker/whatsoever cannot find the mosquitto library located at C:\Program Files\Mosquitto\devel.
Here's the error:
mqtt-hostlink> make
gcc -Wall -o main main.c -LC:\\Program ,_,Files\\Mosquitto\\devel\mosquitto.lib
gcc: error: ,_,Files\Mosquitto\devel\mosquitto.lib: No such file or directory
make: *** [Makefile:11: make] Error 1
Here's my Makefile:
CC = gcc
null :=
SPACE := $(null) $(null)
LIBS = -LC:\\Program$(SPACE),_,Files\\Mosquitto\\devel\mosquitto.lib
%.o: %.c
$(CC) -c -o $# $<
make: main.c
$(CC) -Wall -o main $^ $(LIBS)
.PHONY: clean
The "space" method I referred from : How to escape spaces inside a Makefile
You can just use the short name for tar directory. List the directories with /X option as below
C:\>dir /X p*
Directory of C:\
09/06/2021 02:24 PM <DIR> PROGRA~1 Program Files
09/06/2021 01:29 PM <DIR> PROGRA~2 Program Files (x86)
0 File(s) 0 bytes
Then just use PROGRA~1 instead of Program Files
There's some confusion here. That post is about how to escape spaces from make functions. You are not trying to invoke any make functions here, you are just trying to use a variable in a command line. There's no need to escape anything from make.
What you need to do is escape the spaces from the shell, not from make. You can do that easily, just using quotes. No need for fancy make operations. I recommend you also use forward-slashes, not backslashes. Almost all Windows programs accept both forward and backslashes. Only cmd.exe built-ins don't.
LIBS = "-LC:/Program Files/Mosquitto/devel/mosquitto.lib"
I am trying to create a makefile, for the first time. I went through some tutorials and I managed to create one, but I am having trouble with a couple of things. Below are the details.
Below are the files in the order of execution:
CSV_to_txt.c - no dependency on any other files.
I want to include CSV_files/Equilibrium_trajectories.csv, which is my input, in the make file. Further, I run the command tac Chemical_Equilibrium.txt in the terminal. Can I include this in the make file as well?
fluid_profile.c - depends on pdfutil.h and beta_util.h.
I have the same problem of reading the inputs, for ex:
Enter the number of points
1000 --> to be included in the make file.
This file creates a text file called fluid_points.txt. What I want to include in the makefile is if this file already exists don't execute the command gcc fluid_points.c -o fluid_points.o -lm.
Structure of the make file:
all:
gcc CSV_to_txt.c -o CSV_to_txt.o -lm
./CSV_to_txt.o
#Include the file path and name when asked for it
#ubuntu terminal command --> tac filename.txt > filename_changed.txt
gcc fluid_profile.c -o fluid_profile.o -lm
./fluid_profile.o
#Enter the number of points when prompted to do so
#If fluid_points.txt file is already existing don't execute the above command, instead execute the below one
gcc blah.c -o blah.o -lm
./blah.o
clean:
$(RM) *.o *~
Any sort of help or even a link to a tutorial would be helpful.
A suggested makefile:
run:
.PHONY: run
CSV_to_txt: CSV_to_txt.c
gcc CSV_to_txt.c -o CSV_to_txt -lm
fluid_profile: fluid_profile.c
gcc fluid_profile.c -o fluid_profile -lm
blah: blah.c
gcc blah -o blah.c -lm
run: CSV_to_txt fluid_profile blah
echo "CSV_files/Equilibrium_trajectories.csv" | ./CSV_to_txt.o
tac Chemical_Equilibrium.txt
echo "1000" | ./fluid_profile.o
./blah.o
clean:
$(RM) *.o *~
So, a break down -- first line, predeclare target run, such that it becomes the default target (if you do make, it will run the first target ). Declare this as a phony target (This means there's no actual file called run being produced. You can look up .PHONY for more details)
Then create some rules to generate the executables. Each executable has its own rule to generate it. Typically you would use automatic variables for these like $# and $<, but I wanted to keep it simple for now.
Then the rule for run. This is dependent on the executables (so executables will finish building before this rule runs).
Then, to pass the filename into the executable, you can simply echo the filename, and then pipe that into the executable.
You have a common newbie error... this is to think that a source file depends on other source files (a .c file depends on some .h files) This is an error and probably the cause you are not getting your result.
The objective of a Makefile is to describe file dependencies in order to do the minimum set of commands to build the final target you specify. For this you need to think that a target is something you are goint to create.
Is a source .c file something you create during the build proces? Not, so it cannot be a target of a rule. The target, indeed is the result of the compilation. The source file doesn't depend on a header file... it just includes it to make the compilation of the .o target (this is, actually the target).
Let's say you have a program hello.c that includes modA.h and modB.h. (and even modB.h includes modB2.h) If you modify any of them, you need to recompile hello.c, so your rule will be:
# (1)
hello.o: hello.c modA.h modB.h modB2.h
cc -c hello.c # (2) see below.
(1) a rule line starts at column 1 and has a left hand side (the target file) and a list of sources (dependencies). Each time make sees that the target doesn't exist or has a last change date earlier than the change dates of any of the dependencies, the command lines below are executed, one after the other.
(2) a command rule starts with a <tab> char in the first column of the line. It represents a command (or a list of commands, each in it's command line) that are required to generate the target file from the sources.
a line starting with # is a comment line (also valid to start in the middle of a rule or a command line)
There is anothe type of line (a macro definition) but you need to learn first how to create dependencies and get used to them, before starting learning how to create macros. Read the make(1) doc first.
you see that we only compile hello.c, but we have to do it every time we change any of the other files above. There are two modules, modA.o and modB.o, each of them with their .c file and the includes needed in hello.c. So:
modA.o: modA.c modA.h
cc -c modA.c
modB.o: modB.c modB.h modB2.h
cc -c modB.c
so when we change any of modA.c or modA.h then modA.o will be created. And as modB.h we said above that included modB2.h, then if we modify it, it should be compiled.
Now the dependency of the program to be linked: As the program is compiled, it has just three modules: hello.o, modA.o and modB.o. To create hello all these three modules must be given to the linker.... so the Makefile needs also:
hello: hello.o modA.o modB.o
cc -o hello hello.o modA.o modB.o
and so, the complete Makefile is:
# this rule is put first to become the default target.
# the default target is the final program.
hello: hello.o modA.o modB.o
cc -o hello hello.o modA.o modB.o
# this rule is for the hello.o target only.
hello.o: hello.c modA.h modB.h modB2.h
cc -c hello.c
# this rule is for modA.o
modA.o: modA.c modA.h
cc -c modA.c
# and this one for modB.o
modB.o: modB.c modB.h modB2.h
cc -c modB.c
and with this Makefile you'll enjoy, because you can touch any file, but the compiler will compile only the correct dependencies to generate the final executable program.
Make has a lot of more functionality, but that requires you to know at least the most basic of it. Once after you have succeeded on the creation of the correct dependencies, you can start to study the other facilities of make, that are only there to abbreviate/avoid rewritting the same thing several times. But read at least the make manual page.
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.
When I execute several different compilation commands via a makefile on one specific sourcecode (c-code). Is there a way to add these compilation commands as a comment to the source code for documentation reason?
You can do it by adding a preprocessor macro defined as a string containing the compiler flags, and then use this macro in an assignment to a constant string pointer.
Something like this in the Makefile
$(CC) $(CFLAGS) -DCFLAGS="$(CFLAGS)" ...
And in one source file do e.g.
const char cflags[] = CFLAGS;
There is no generic way to get it as a part of a comment though.
You could have a special marker in a comment block in a source file, and replace that using e.g. sed in a POSIX enviromnent (like Linux or OSX).
Something like this:
sed -i.bak -e 's#// CFLAGS: .*$#// CFLAGS: $(CFLAGS)#' some_source_file.c
Maybe I misunderstand the question, but this doesn't seem too difficult:
foo.o: foo.cc
#command="$(CXX) $(CPPFLAGS) -c $< -o $#"; echo $$command ;\
sed -i .bak "1{x;s|^|//$$command|;G;}" $< ; \
$$command