Automatically create .OBJDIR subdirectories - makefile

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.

Related

Can GCC ignore nonexisting directories?

I have two projects: mylib and myproj
mylib compiles into a shared object.
myproj uses mylib.
I linking myproj using:
g++ -L../../mylib/Release myproj.o -lmylib
That works fine on my development machine.
On another machine, mylib.so is located in /usr/local/lib. Therefore there is no need for -L.
It compiles fine without the -L.
But, once I compile it with the same command (with the -L), it responds with
g++: error: ../../mylib/Release: No such file or directory
I would like myproj to compile on both machines with the same command.
Is there a way to make it ignore non existing directories?
It doesn't seem to care whether a full path doesn't exist, it complains only for relative paths.
You want to use Makefiles as often as you can since they make things a lot easier. In a defined Makefile you could check for the directory first. It could be sth like this:
all:
if [ -d "mylib" ]; then
g++ -L../../mylib/Release myproj.o -lmylib
else
g++ myproj.o -lmylib
fi
Of course you can use Variables like CC, etc. This is just a basic example.

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

How to modify implicit GNUMake rules to compile files?

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

Library Linking

I am trying to learn to C programing using Zed Shaw's Learn C the hard way. I have been working on ex26 where we create a program "devpkg" used to install software. This exercise requires installing Apache Portable Runtime library. After writing the code for this exercise I could not get program to compile using the following makefile:
PREFIX?=/user/local
CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 -I{PREFIX}/apr/include/apr-util-1
LDFLAGS=-L${PREFIX}/apr/lib -lapr-1 -pthread -laprutil-1
all: devpkg
install: all
install -d${DESTDIR}/${PREFIX}/bin/
install devpkg ${DESTDIR}/${PREFIX}/bin/
clean:
rm -f *.o
rm -f devpkg
rm -f *.dSYM
This makefile did not seem to work as when I used "$make devpkg" not all of the APR library functions were declared. As a side note I am running this on a Ubuntu virtual machine. A solution given in the text says to alter a config file and then "run ldconfig" to help the linker find the appropriate library.
I do not understand the man page for ldconfig well enough to correctly utilize the function. How do run ldconfig correctly?
Also after some digging I found a reference that using "LDLIBS" instead of "LDFLAGS" in the makefile fixed the problem. I altered the makefile and the program compiled.
What is the difference between "LDFLAGS" and "LDLIBS" that allowed the C compiler to correctly link to the APR library? Is there a handy list of commands somewhere that can help me better understand how a makefile is correctly generated?
Thanks for your time.
From the GNU Make Manual, section 10.2 Catalogue of Implicit Rules:
Linking a single object file
n is made automatically from n.o by running the linker (usually called ld) via the C compiler. The precise recipe used is '$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)'.
As you can see, LDFLAGS comes before your object file and LDLIBS after. Sometimes that order can matter - apparently it does in your case.
Editorial note: While it might sometimes be convenient to use make's implicit rule support, it almost always ends up more confusing down the road. I'd urge you to write a complete makefile - it'll help you understand what's going on better and hopefully avoid this sort of problem in the future.
I just wanted to add this answer as an alternative to changing "LDFLAGS" to "LDLIBS". The above solution did work in my case but I found an alternative (though less direct) solution before I saw this thread which others may find useful or interesting. When compiling I was seeing lots of "undefined reference" errors e.g.:
/MyCode/LCTHW/devpkg/devpkg.c:18: undefined reference to `apr_pool_initialize'
After much trial and error, I changed the makefile thus (still using LDFLAGS):
CC=gcc
PREFIX?=/usr/local
CFLAGS=-g -Wall -I$(PREFIX)/apr/include/apr-1 -I$(PREFIX)/apr/include/apr-util-1
LDFLAGS=-L$(PREFIX)/apr/lib -lapr-1 -laprutil-1 -pthread
OBJECTS=bstrlib.o db.o shell.o commands.o devpkg.o
all: devpkg
devpkg: $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o devpkg $(LDFLAGS)
install: all
install -d $(DESTDIR)/$(PREFIX)/bin/
install devpkg $(DESTDIR)/$(PREFIX)/bin/
clean:
rm -f *.o
rm -f devpkg
rm -rf *.dSYM
I then had to add a .conf file to /etc/ld.so.conf.d containing the path to the apr libraries, namely
/usr/local/apr/lib
And then run
sudo ldconfig
so the system would pick up the new .conf file and so know where to find the library. From what I have read, it seems this last step was necessary because the library wasn't stored in /usr/local/lib. If I remove the .conf file and re-run ldconfig to update, the program compiles but then fails to find the libraries at run-time (whether compiled with my makefile or OP's).
While I don't fully understand my solution, it at least allowed me to compile and run the program with no errors. Hopefully this solution will be of interest to others, and maybe somebody more knowledgeable will be able to explain in more detail why it works.

Resources