How to modify implicit GNUMake rules to compile files? - makefile

GNUMake has implicit rules to compile certain file types, for instance, in my directory if I have a file 1.cpp, and I write on terminal make 1, the following command gets executed:
g++ 1.cpp -o 1
All this happens without any Makefile in the directory, due to implicit Make rules. However, I am unable to figure out how to modify these rules for my benefit. For instance, if I need to compile my file like this:
g++ -std=c++14 -O2 -g -w -o 1 1.cpp
and for doing this, I want to run the command: make 1, it should do it. Also, it should be generic for any file, for instance I now create a file 2.cpp and write make 2, it should compile it and produce the executable, even if there is no rule for 2 in my Makefile.
Also, if I now go to another directory where this explicit rule has not been mentioned, it should compile according to the default implicit rules only. How to I achieve this?

One way is to set the variables used by the implicit rules in your environment
set CXXFLAGS="-std=c++14 -O2 -g -w"
If you only want this to apply to a single directory, then place a Makefile in the directory with the following
CXXFLAGS := -std=c++14 -O2 -g -w

Related

Run two instances of the same C++ program simultaneously

I've got a C++ program with a Makefile, building (g++) and running on Windows cmd. Thing is, sometimes it takes a while to run and save the results, and I want to run it with different parameters at the same time so that I can do something else while I wait for the first instance to finish. It doesn't work though, because of the executable I guess:
>make
g++ -c -o main.o main.cpp
Assembler messages:
Fatal error: can't create main.o: Permission denied
make: *** [main.o] Error 1
You have two problems: The one you ask about, and the reason you ask this question in the first place.
Lets start with the problem you have...
Judging by the Makefile you show, you have it all wrong.
Rules are in the format
target: sources_the_target_depend_on
The target is usually a file that need to be created. For an object file that is the name of the actual object file itself. The source files that the object files then depend on should be on the right-hand side.
To take an example from you Makefile (before you edited it away):
graph2: graph2.o
g++ -g -c graph.cpp -o graph2.o
Here you tell make that the file graph2 depends on the file graph2.o, and then it creates the graph2.o file. That's wrong. The rule should be that the file graph2.o depends om the file graph.cpp and go on to generate the file graph2.o:
graph2.o: graph.cpp
g++ -g -c graph.cpp -o graph2.o
This indirectly leads to the problem you have, with this line (deduced from your error and the Makefile):
main: main.o utils.o graph.o heuristics.o
g++ -g main.cpp -o main.o utils.o graph.o heuristics.o
This contains the same error as discussed above: You say that the file main depends on main.o and then the rule create main.o. Your rule should be
main: main.cpp utils.o graph.o heuristics.o
g++ -g main.cpp -o main utils.o graph.o heuristics.o
Note also how I no longer name the executable file main.o, as that is supposed to be used for object files.
Now lets continue with the reason you have the problem in the first place: That you need to edit the code to change data or values.
This is a problem that you need to solve. One common way to solve it is through command line arguments. If your program parses the command line arguments passed to your program you can pass it the values that could change from run to run.
How to do this is whole chapter on its own, so I wont give you any more details. There are plenty of tutorials online.
Lastly, you can simplify your Makefile considerably, by using implicit rules and variables.
I would simply create the Makefile to look something like this
# The compiler to use
CXX = g++
# Flags to pass to the compiler (add warnings when building)
CXXFLAGS = -Wall
# The main executable file to generate
TARGET = main
# List the object files needed to generate the main executable file
OBJECTS = main.o utils.o graph.o heuristics.o
# The all target depends on your main executable file
# Also as the first target in the Makefile, if no specific target is specified
# this will be the one that is used (it's the "default" target for the Makefile)
all: $(TARGET)
# The main executable file depends on the object files
$(TARGET): $(OBJECTS)
This is really it. the object files will be built automatically from their respective source files, and then the executable program will be linked using the object files listed.

Cannot pass flags to Makefile to compile my code

I have a project that basically compiles from the command line in the following form:
g++ -o stack_raster stack_raster.cpp -lgdal -lboost_filesystem -lboost_system
I made a Makefile, and this is the content:
CXX =g++
LDDFLAGS = -lgdal -lboost_system -lboost_filesystem
all: clean stack_raster
clean:
rm -f stack_raster
However I got a collect2: error: ld returned 1 exit status.
A second variation of my Makefile I tried was:
CXX = g++
CPPFLAGS = -lgdal -lboost_system -lboost_filesystem
all: clean stack_raster
clean:
rem -f stack_raster
but I still receive the following message (even though the compile flags appear as they should for my program to compile successfully).
collect2: error: ld returned 1 exit status
<builtin>: recipe for target `stack_raster` failed
make: *** [stack_raster] Error 1
Does anyone could help me with a reference or hint about my problem, and how could I tackle it?
Does anyone could help me with a reference or hint about my problem, and how could I tackle it?
To begin with, you should have a look at the actual link command that make executed. It should have been echoed to make's output just before the error message from collect2. Understanding what's wrong with the command is the first step in determining how to fix your makefile.
In the first case, the command is probably something like
g++ stack_raster.cpp -o stack_raster
In the second, it is probably something like
g++ -lgdal -lboost_system -lboost_filesystem stack_raster.cpp -o stack_raster
The latter is probably also very similar to what you would get with the first makefile if you corrected the spelling of LDDFLAGS to LDFLAGS.
You will note that the library flags come in a different place in that command than they do in your manual command, and I assume you know that the order of objects and library flags on the linker command line is significant to Unix-style linkers such as GNU's (which is the one that the g++ driver will use).
You can certainly fix this by writing an explicit rule, as you describe in your own answer, but your makes' built-in rules may be up to the task, too. If you are using GNU make then they certainly are. For this purpose it is useful to know what the built-in rules actually are, and essential to know what the variables on which these rules depend mean.
Specifically,
LDFLAGS provides options to pass when invoking the linker, and conventionally, they appear on the command line before the objects being linked. As a result, this variable typically is not appropriate for specifying libraries (but it is fine for other link-specific options, such as -L to add directories to the library search path).
CPPFLAGS provides options for modulating the behavior of the C preprocessor (including when compiling C++). These do not typically appear at all in link(-only) commands executed by make, but they will appear (early) in commands for compiling object files from C or C++ sources, and in rules for building executables directly from C or C++ sources.
Neither of those is what you want, but if you are using GNU make, then its documentation for the former explicitly tells you what (with that make implementation) you should do instead:
Extra flags to give to compilers when they are supposed to invoke the
linker, ‘ld’, such as -L. Libraries (-lfoo) should be added to the
LDLIBS variable instead.
(emphasis added)
In GNU make, and perhaps some others, the LDLIBS variable serves exactly the purpose you need: to specify the libraries to link. These will appear at the end of the link command line from built-in rules, as you can confirm from GNU make's catalog of implicit rules, or from the list obtainable by running make -p in a directory containing no makefile.
So, with GNU make you can get the build you seem to want from the built-in rules, with this:
CXX = g++
LDLIBS = -lgdal -lboost_system -lboost_filesystem
all: clean stack_raster
clean:
rm -f stack_raster
In closing, I note that cleaning before building by default, as your examples do and mine imitates, largely defeats the purpose of using make instead of a simple script. Part of the point of make is to do the minimum work necessary, and if your target executable is present and not out of date with respect to its sources then there is no reason to force it to be rebuilt.
Check out the answer:
Set up my makefile to compile C with just "make"
YOu have to specify in the Makefile the file you want to create in this case stack_raster.exe and the objective file in this case stack_raster.cpp and specify the command line arguments you normally pass for compiling. So the Makefile would be something like:
CXX=g++
stack_raster.exe: stack_raster.cpp
g++ -o stack_raster.exe stack_raster.cpp -lgdal -lboost_filesystem -lboost_system
all: clean stack_raster.exe
clean:
rm -f stack_raster.exe

Automatically create .OBJDIR subdirectories

OS: FreeBSD 11.0-RELEASE
I have the following directory structure:
/xxx/obj/
/xxx/src/deep.cpp
/xxx/flat.cpp
/xxx/makefile
The content of makefile is as follows:
flat.out: flat.o
deep.out: src/deep.o
I have no problem building flat:
/xxx $ make flat.out
c++ -O2 -pipe -c /xxx/flat.cpp -o flat.o
cc -O2 -pipe flat.o -o flat.out
/xxx $ ls obj
flat.o flat.out
But when I try to build deep it fails:
/xxx $ make deep.out
c++ -O2 -pipe -c /xxx/src/deep.cpp -o src/deep.o
error: unable to open output file 'src/deep.o': 'No such file or directory'
1 error generated.
*** Error code 1
Stop.
make: stopped in /xxx
If I then create /xxx/obj/src manually it succeeds:
/xxx $ mkdir obj/src
/xxx $ make deep.out
c++ -O2 -pipe -c /xxx/src/deep.cpp -o src/deep.o
cc -O2 -pipe src/deep.o -o deep.out
/xxx $ ls obj
deep.out flat.o flat.out src
/xxx $ ls obj/src
deep.o
According to this source bmake (aka bsdmake?) supports automatic creation of out-of-source OBJDIRs, but I cannot figure out how exactly.
How do I configure bmake to create the relevant directories automatically, in the general case?
Automatic creation of out-of-source OBJDIRs is supported but not in the sense you seem to expect it. Creation of out-of-source OBJDIRs can be implemented with bmake(1) directives but is not supported by the bmake(1) program itself. That said,
If you use bmake(1) directives shipped with FreeBSD to build your project, then the creation of OBJDIRs is supported and implemented by the obj target, so that the command make obj will create the OBJDIRs. See the file bsd.obj.mk for further documentation and implementation details. FreeBSD sources contain a lot of examples of programs using these directives to build.
If you use bmake(1) directives shipped as the (portable) bsdowl package, then the creation of OBJDIRs is supported and implemented by the target obj so that the command make obj or the command make preparatives using a more general target will create the OBJDIRs. The example directory contains several C-based examples showing how to prepare your Makefiles to build your project with the bsdowl package.
If you use custom bmake(1) directives, then you will have to implement a target taking care of this creation yourself. The file bsd.obj.mk is definitely a good source to get started with this.
An important point to note, is that bmake(1) determines its actual working directory before processing any targets, which means that it is almost always the right thing to do to execute the target requesting the creation of OBJDIRs on its own. Because of this, the command bmake obj all from your example would fail with the same error message you reported above. The correct invocation would instead be bmake obj && bmake all, since the second bmake(1) process has now the chance to change to the OBJDIR created by the previous run.

Cannot specify include file with make and MinGW

I'm facing an issue with a simple makefile and gcc (MinGW with Windows 10).
This is my simple makefile
IJNI=-I"C:\Program Files (x86)\Java\jdk1.7.0_79\include"
IJNIWIN32=-I"C:\Program Files (x86)\Java\jdk1.7.0_79\include/win32"
CC=gcc
default: main
main: lowlevelAccess.o
$(CC) $(IJNI) $(IJNIWIN32) -c lowlevelAccess -o lowlevelAccess.o
When from a command promp I launch make, I obtain:
gcc -c -o lowlevelAccess.o lowlevelAccess.c
lowlevelAccess.c:7:17: fatal error: jni.h: No such file or directory
#include <jni.h>
^
compilation terminated.
make: *** [lowlevelAccess.o] Error 1
What is wrong?
Thank you!
You aren't adding your -I flags on the lowlevelAccess.o compilation but that's the rule that needs it (not the linking rule where you have it now).
Try adding CFLAGS += $(IJNI) $(IJNIWIN32) to your makefile (possibly use CPPFLAGS instead I'm not sure offhand which is technically more correct here).
See Variables Used by Implicit Rules for what those variables are and Catalogue of Built-In Rules (or the output from make -qp) to see what the default rules that use those variables look like.

Trouble with simple makefile in C

I am somewhat of a beginner in C and have a project due where I need to include a makefile to compile my single file program that uses pthreads and semaphores. My makefile looks like:
# Makefile for pizza program
pizza: pizza.o
gcc -lrt -lpthread -g -o pizza pizza.o
pizza.o: pizza.c
gcc -lrt -lpthread -g -c pizza.o pizza.c
and I keep getting:
make: Nothing to be done for 'Makefile'.
I have done several makefiles before and have never gotten this message. I've tried different semantics in the makefile and have only gotten this same message. And yes, the command is tabbed after the target and dependency line.
Using gcc on tcsh. I have read other makefile posts on SO but I wasn't able to use any of the answers to figure it out for my case.
Any help would be greatly appreciated!
The arguments to make are the targets to be built.
You are running make Makefile which is telling make to try to build the Makefile target.
There is no such target in your makefile, make has no built-in rule that applies to that target and the file exists (and is assumed to be up-to-date) which is what that message is telling you.
To run the default target (by default the first target listed) you can just run make (assuming you are using a default name like Makefile for your makefile).
You can also use the -f argument to make to select an alternate makefile name.
So make -f Makefile will in this case (since Makefile is a default searched name) do the same thing as make.

Resources