I think it will be good and not much bad if -Wall flag is switched on by default. How do I configure GCC like this?
Is there any drawbacks to this other than the fact that a lot of warnings will flood your terminal when you are compiling some large program from source?
Add these lines to your ~/.bashrc if you use bash as your shell.
alias gcc='gcc -Wall'
Update:
you can refer to this question on https://superuser.com/questions/519692/alias-gcc-gcc-fpermissive-or-modifying-configure-script
If you use make, you need to overwrite make's variables CC and CXX from within the .bashrc:
export CC="gcc -wall"
export CXX="g++ -wall"
juzzlin suggested that a good method would be to write a wrapper for gcc. Marc Glisse also suggested that writing one is the best way to achieve what I want. So that's just what I did.
I made a bash script that calls gcc for me:
#!/bin/sh
echo -n "Compiling $1..."
gcc -Wall -Werror -o $(basename $1 .c).out $1
a=$?
if [[ "$a" -eq 1 ]]; then
echo "Failed!"
else
echo "Done."
echo "Executing:"
./$(basename $1 .c).out
fi
Then I copied the script to /usr/bin and made it executable:
sudo cp car /usr/bin
chmod +x /usr/bin/car
(The name of the script is car which stands for "Compile And Run")
So whenever I want to compile a source file and run it, I will type:
car mysourcefile.c
As discussed in the comments (although it's not a direct answer to your question), using a Makefile has many benefits. It provides a place where to put your build commands, that will alway stay up to date if you only build with make. It also ease running tests at each build.
Writing tests is a good habit, even when you're just working on a small and unsignificant piece of code for homeworks. It allows you to spot some dumb mistakes that you would otherwise miss, and to be sure you don't break your existing code by modifying it (especially the last minute modification).
An example of such a Makefile (here I have nothing to build apart from the test because it's a header only component):
all:
g++ -O2 -Wall -Werror -std=c++11 test_polynomial.cc -o test_polynomial -lgmp
g++ -O2 -Wall -Werror -std=c++11 test_g2polynomial.cc -o test_g2polynomial
./test_polynomial --log_level=test_suite
./test_g2polynomial --log_level=test_suite
clean:
rm -f test_polynomial test_g2polynomial
Note: The example is not a very good one as I don't even factorize the build options in CFLAGS. If I want to add a flag, I have to add it in both commands !
Another benefit is that you always run make to build, whatever the language, the dependencies or even the build system (when working on a project using scons or another build system, I still write a Makefile doing all the commands I do when building and testing !).
This allows my personal addition on it (but here we're completely off-topic): I have a build script named autobuild looping on make each time I write a file in vim. I code in screen and run autobuild in a small window at the bottom of my screen. This way, each change is built and tested as soon as I write the file.
Related
I have a reasonably large project (4272 .o files) and I can't get it to link with GNU Make. I run into make: /bin/sh: Argument list too long. This is a Qt 5 project that uses qmake to generate the makefile.
I know there are lots of questions about this, but I don't know how to apply any of the solutions to my problem. I'm also not totally sure why I'm running into this at the linking step. The error I get is:
make: /bin/sh: Argument list too long
The makefile entry for linking my project looks like this:
build/debug/my_target/my_target: $(OBJECTS)
#test -d build/debug/my_target/ || mkdir -p build/debug/my_target/
$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
which expands to something like:
#echo linking /build/debug/my_target/my_target && clang++ -ccc-gcc-name g++ -lc++ -L/path/to/licensing/lib -Wl,-rpath,/path/to/qt/lib -Wl,-rpath-link,/path/to/qt/lib -o build/debug/my_target/my_target build/debug/my_target/obj/object1.o build/debug/my_target/obj/object2.o ... build/debug/my_target/obj/object4272.o ... [ a bunch of moc_X.o ] ... [ a bunch of libs ] -lGL -lpthread -no-pie
This is pretty long. But here's where it gets weird: when I put the expanded command after the #echo linking build/debug/my_target/my_target && into a shell script, and it runs. The shell script is 202,420 characters (including the #!/bin/sh line). Also, if I get rid of the #echo ... && part of the command I can run make and linking works.
Another workaround: if I manually edit my makefile so that the linking command contains build/debug/my_target/*.o instead of $(OBJECTS) it works:
build/debug/my_target/my_target: $(OBJECTS)
#test -d build/debug/my_target/ || mkdir -p build/debug/my_target/
$(LINK) $(LFLAGS) -o $(TARGET) build/debug/my_target/*.o $(OBJCOMP) $(LIBS)
I don't think I can get qmake to do this, though, so I'm stuck manually editing my makefile unless I can find another solution.
Answers to similar problems seem to focus on line breaks and how they're handled in makefiles. My shell script only has two lines (one after #!/bin/sh and one after the actual command). Also, one solution that people have come up with (for example this one) uses a for loop to iteratively run a command on each argument. I'm not sure how I could apply this here, since (I think) I need all those object files in my linker command.
How does #echo cause the max argument length to be exceeded?
Questions I originally asked that aren't really relevant:
(Note: as originally posted this question missed the #echo at the beginning of the linking command. That seems to be the answer to "why is this happening" and as such I don't really need to know the answer to the second question, which is answered in the first comment in any case).
Why is this happening? How is it that make is running into this error with a command that I can apparently run in a shell script?
How can I get around this if there's no way to run my command as an iterative series of shorter commands?
Various details about my system that might be relevant:
I'm running a fairly up-to-date Arch Linux system, kernel 5.8.10
ARG_MAX value is 2097152, the output from xargs --show-limits is:
Your environment variables take up 2343 bytes
POSIX upper limit on argument length (this system): 2092761
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2090418
Size of command buffer we are actually using: 131072
Maximum parallelism (--max-procs must be no greater): 2147483647
ulimit -s output: 8192 (I've tried setting this to much larger values, e.g. ulimit -s 65536 without success, which maybe isn't surprising since ARG_MAX appears to be much larger than the linker command).
GNU Make version is 4.3
clang/clang++ version is 10.0.1
Qt version is 5.15.1 (I'm fairly certain this isn't relevant, we've just switched our project over from 5.9.6 and I had the same problem then as well).
Just FYI, the reason removing the echo fixes the problem (this is what I was going to suggest as well) is that when you remove the special shell operator && and just have a simple command invocation with no shell features like multiple commands, special quoting, globbing, etc. then make uses the "fast path" to invoke your command.
That is, if make can determine that the shell would do nothing special with your command, other than run it, make will skip invoking the shell and instead run your command directly.
In that case you will not run up against the single-argument limit because it doesn't use the /bin/sh -c '...' form.
Of course, this can be a little magical and inflexible since you have to be careful to ensure no special shell operations are ever included in your link line. But if you can ensure this then it should solve your problem.
Why is this happening? How is it that make is running into this error with a command that I can apparently run in a shell script?
Because make is running the shell commands (recipes) by passing them as a single argument to /bin/sh -c, and not only will that run into the OS's limit on command line arguments + environment variables, but also into the much lower limit that Linux is imposing on a single string from the command line or environment, which is usually 128k bytes.
How can I get around this if there's no way to run my command as an iterative series of shorter commands?
As suggested by #ephemient can use the #arglist argument of gcc or ld (which directs it to take its arguments from a file), and use the file function of GNU make to create that arglist file, which being internal to make, will not run into any that OS limit.
I want to run my program with an executable without the "./"
For example lets say I have the makefile:
all: RUN
RUN: main.o
gcc -0 RUN main.o
main.o: main.c
gcc -c main.c
So in order to run the program normally I would say in the terminal "make" then put "./RUN" to invoke the program.
But I would just like to say in the terminal "make" then "RUN" to invoke the program.
So to conclude I would just like to say >RUN instead of >./RUN inside the terminal. Is there any command I can use to do this inside the Makefile?
When I just put "RUN" in the terminal it just says command not found.
It is a matter of $PATH, which is imported by make from your environment.
You might set it in your Makefile, perhaps with
export PATH=$(PATH):.
or
export PATH:=$(shell echo $$PATH:.)
but I don't recommend doing that (it could be a security hole).
I recommend on the contrary using explicitly ./RUN in your Makefile, which is much more readable and less error-prone (what would happen if you got a RUN program somewhere else in your PATH ?).
BTW, you'll better read more about make, run once make -p to understand the builtin rules known to make, and have
CC= gcc
CFLAGS+= -Wall -g
(because you really want all warnings & debug info)
and simply
main.o: main.c
(without recipes in that rule) in your Makefile
change your makefile to
all: RUN
RUN: main.o
gcc -o RUN main.o && ./RUN
main.o: main.c
gcc -c main.c
just put ./filename in your makefile
For example, I have something like this in my makefile:
all:
cd some_directory
But when I typed make I saw only 'cd some_directory', like in the echo command.
It is actually executing the command, changing the directory to some_directory, however, this is performed in a sub-process shell, and affects neither make nor the shell you're working from.
If you're looking to perform more tasks within some_directory, you need to add a semi-colon and append the other commands as well. Note that you cannot use new lines as they are interpreted by make as the end of the rule, so any new lines you use for clarity need to be escaped by a backslash.
For example:
all:
cd some_dir; echo "I'm in some_dir"; \
gcc -Wall -o myTest myTest.c
Note also that the semicolon is necessary between every command even though you add a backslash and a newline. This is due to the fact that the entire string is parsed as a single line by the shell. As noted in the comments, you should use '&&' to join commands, which means they only get executed if the preceding command was successful.
all:
cd some_dir && echo "I'm in some_dir" && \
gcc -Wall -o myTest myTest.c
This is especially crucial when doing destructive work, such as clean-up, as you'll otherwise destroy the wrong stuff, should the cd fail for whatever reason.
A common usage, though, is to call make in the subdirectory, which you might want to look into. There's a command-line option for this, so you don't have to call cd yourself, so your rule would look like this
all:
$(MAKE) -C some_dir all
which will change into some_dir and execute the Makefile in that directory, with the target "all". As a best practice, use $(MAKE) instead of calling make directly, as it'll take care to call the right make instance (if you, for example, use a special make version for your build environment), as well as provide slightly different behavior when running using certain switches, such as -t.
For the record, make always echos the command it executes (unless explicitly suppressed), even if it has no output, which is what you're seeing.
Starting from GNU make 3.82 (July 2010), you can use the .ONESHELL special target to run all recipes in a single instantiation of the shell (bold emphasis mine):
New special target: .ONESHELL instructs make to invoke a single instance of the shell and provide it with the entire recipe, regardless of how many lines it contains.
.ONESHELL: # Applies to every targets in the file!
all:
cd ~/some_dir
pwd # Prints ~/some_dir if cd succeeded
another_rule:
cd ~/some_dir
pwd # Prints ~/some_dir if cd succeeded
Note that this will be equivalent to manually running
$(SHELL) $(.SHELLFLAGS) "cd ~/some_dir; pwd"
# Which gets replaced to this, most of the time:
/bin/sh -c "cd ~/some_dir; pwd"
Commands are not linked with && so if you want to stop at the first one that fails, you should also add the -e flag to your .SHELLFLAGS:
.SHELLFLAGS += -e
Also the -o pipefail flag might be of interest:
If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.
Here's a cute trick to deal with directories and make. Instead of using multiline strings, or "cd ;" on each command, define a simple chdir function as so:
CHDIR_SHELL := $(SHELL)
define chdir
$(eval _D=$(firstword $(1) $(#D)))
$(info $(MAKE): cd $(_D)) $(eval SHELL = cd $(_D); $(CHDIR_SHELL))
endef
Then all you have to do is call it in your rule as so:
all:
$(call chdir,some_dir)
echo "I'm now always in some_dir"
gcc -Wall -o myTest myTest.c
You can even do the following:
some_dir/myTest:
$(call chdir)
echo "I'm now always in some_dir"
gcc -Wall -o myTest myTest.c
What do you want it to do once it gets there? Each command is executed in a subshell, so the subshell changes directory, but the end result is that the next command is still in the current directory.
With GNU make, you can do something like:
BIN=/bin
foo:
$(shell cd $(BIN); ls)
Here is the pattern I've used:
.PHONY: test_py_utils
PY_UTILS_DIR = py_utils
test_py_utils:
cd $(PY_UTILS_DIR) && black .
cd $(PY_UTILS_DIR) && isort .
cd $(PY_UTILS_DIR) && mypy .
cd $(PY_UTILS_DIR) && pytest -sl .
cd $(PY_UTILS_DIR) && flake8 .
My motivations for this pattern are:
The above solution is simple and readable (albeit verbose)
I read the classic paper "Recursive Make Considered Harmful", which discouraged me from using $(MAKE) -C some_dir all
I didn't want to use just one line of code (punctuated by semicolons or &&) because it is less readable, and I fear that I will make a typo when editing the make recipe.
I didn't want to use the .ONESHELL special target because:
that is a global option that affects all recipes in the makefile
using .ONESHELL causes all lines of the recipe to be executed even if one of the earlier lines has failed with a nonzero exit status. Workarounds like calling set -e are possible, but such workarounds would have to be implemented for every recipe in the makefile.
To change dir
foo:
$(MAKE) -C mydir
multi:
$(MAKE) -C / -C my-custom-dir ## Equivalent to /my-custom-dir
PYTHON = python3
test:
cd src/mainscripts; ${PYTHON} -m pytest
#to keep make file in root directory and run test from source root above #worked for me.
Like this:
target:
$(shell cd ....); \
# ... commands execution in this directory
# ... no need to go back (using "cd -" or so)
# ... next target will be automatically in prev dir
Good luck!
I've written the following Makefile:
INTERACTION=nonstopmode
all:
make read.pdf > /dev/null
make clean > /dev/null
diagnostic:
INTERACTION=batchmode
make read.pdf
make clean
%.pdf: %.tex biblio.bib
bash makepdf.sh $(INTERACTION) $<
clean:
rm -f *.aux *.log *.bbl *.bak *.blg *.toc *.out *.glg *.glo *.gls *.ist *~ *.*~* *.backup
The Makefile provides two modes: a simple make file that doesn't output error and warning messages and a diagnostic mode such that pdflatex interacts with the user in order to locate the problem.
The makepdf.sh looks as follows:
filename=$(basename $2)
filename="${filename%.*}"
pdflatex -interaction=$1 $2
makeglossaries "$filename" 2
makeindex "$filename" 2
pdflatex -interaction=$1 $2
echo $1
Regardless of the fact whether make or make diagnostic is called, the program always runs in nonstopmode. Can't a Makefile variable been overwritten? If so, how can this problem be resolved? Otherwise, what is wrong with this code?
This makefile is quite strange. Basically, not written correctly.
The most direct answer to your question is for you to realize that every line in a makefile recipe is invoked in a separate shell, and in UNIX/POSIX systems it's not possible for a process to impact the environment of its parent. That means that changes made to the environment in the shell that make invokes have no effect on the make process, or on any subsequent shells. So INTERACTION=batchmode is run in a shell and sets the INTERACTION variable to batchmode, then the shell exits and that setting is forgotten, then the next line is run with the previous setting. If you want variables to take effect you have to put them in the same logical line in the recipe.
However, there are even more fundamental problems with this makefile. First, you should never run make to invoke a recursive make. Always use the $(MAKE) variable.
Second, you shouldn't be running sub-makes anyway. The entire purpose of listing prerequisites in a makefile is to enforce an order on invocation of the rules; here you're trying to take over make's job by running commands recursively.
Third, assuming you're using GNU make you can use target-specific variables for what you want to do much more easily (see the GNU make manual). For example your makefile can be more correctly written like this (note, no recursion at all!):
INTERACTION = nonstopmode
all: read.pdf
diagnostic: INTERACTION = batchmode
diagnostic: all
%.pdf: %.tex biblio.bib
bash makepdf.sh $(INTERACTION) $<
clean:
rm -f *.aux *.log *.bbl *.bak *.blg *.toc *.out *.glg *.glo *.gls *.ist *~ *.*~* *.backup
It doesn't run the clean rule automatically after each build.
I've come across this task to build a Makefile for a program in assembly language I made (nothing fancy, like a hello world). The program is in Linux 32 bits and I'm using NASM assembler. So far I can only find Makefiles for programs for C, I'm aware that there's not much difference from one to another but I'm not familiar with this thing. What I have is this:
Program: main.o
gcc -o Program main.o
main.o: main.asm
nasm -f elf -g -F stabs main.asm
I can't tell whether this is correct or, if it does, how it works. I can't try the code because this computer doesn't have Linux. I really would like to know what's going on in the code.
First of all, read an introduction to Makefile.
Your Makefile is read by the make program on invocation. It executes either the given rule (e.g. make clean) or executes the default one (usually all).
Each rule has a name, optional dependencies, and shell code to execute.
If you use objects file you usally start your Makefile like that:
all: main.o
gcc -o PROGRAM_NAME main.o
The dependency here is main.o, so it must be resolved before the execution of the code. Make searches first for a file named main.o and use it. If it doesn't exist, it search for a rule permitting to make the file.
You have the following:
main.o: main.asm
nasm -f elf -g -F stabs main.asm
Here the rule to make main.o depends on main.asm, which is your source file so I think it already exists. The code under the rule is then executed and has to make the file matching the rule name.
If your nasm invocation is correct, then the file is created and the code of the all (or Program as you named it) is executed.
So your Makefile should work, you just have to test it to be sure :) It is barely the same as invoking:
nasm -f elf -g -F stabs main.asm && gcc -o Program main.o
As a side note, you can still test this on windows as long as you have all the tools installed. The cygwin project provides an environment where you can install make, gcc and nasm.