I am trying to build the Atmel BitCloud v3.2 sample application Blink with the makefile in Linux and Mac. Everything works fine in Windows. But in Posix-like systems the following lines are not working:
all: directories images root_files size
$(OBJ_PATH)/%.o: $(SRCS)
$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $#)), $(SRCS)) -o $#
Therefore, the compiler is not being executed and object files are not being created. As the result the linker displays error messages such as
avr-gcc: error: All_MegaRf_Atmega256rfr2_8Mhz_Gcc/Obj/blink.o: No such file or directory
The line $(OBJ_PATH)/%.o: $(SRCS) is the source of the problem.
If I substitute it with smth like $(OBJ_PATH)/blink.o: ../../src/blink.c the corresponding object-file is being successfully created.
I was even able to build the whole application by manually setting build targets as follows:
$(OBJ_PATH)/blink.o: ../../src/blink.c
$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $#)), $(SRCS)) -o $#
$(OBJ_PATH)/stdPdsEvents.o: ../../../../BitCloud/Components/PersistDataServer/std/src/stdPdsEvents.c
$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $#)), $(SRCS)) -o $#
for all the .c files in the project.
The list of sources on the other hand is defined like this:
SRCS = \
../../src/blink.c \
../../../../BitCloud/Components/PersistDataServer/std/src/stdPdsMemAccess.c \
../../../../BitCloud/Components/PersistDataServer/std/src/stdPdsTimer.c \
Can anyone help me to figure out why is the pattern matching not working and how to recover it.
Note: Similar topic has already been open here, but the solution found by th author himself wasn't explained well in my opinion, so I couldn't solve my problem.
The construct to have each object file depend on all source files and then have the compilation step fish the actually useful file out of the list of sources is quite dubious. A better approach would be to generate a Makefile snippet and include it, something like this:
makefile.d:
echo "$(SRCS)" \
| tr ' ' '\n' \
| sed -n 's%\(.*\)/\([^/]*\)\.c$$%$(OBJ_PATH)/\2.o: \1/\2.c%p' >$#
include makefile.d
All details of sed are not properly standardized, so you may be better off rewriting the substitution in Perl or something. The beef here is how we capture the path and the base name and generate a specific rule for each dependency.
Managed to solve it finally.
In order to make it compile both in Windows and Linux one should change the makefile as shown below:
objects := $(patsubst %.c,$(OBJ_PATH)/%.o,$(notdir $(SRCS)))
$(objects): $(SRCS)
#$(OBJ_PATH)/%.o: $(SRCS)
$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $#)), $(SRCS)) -o $#
where $(OBJ_PATH)/%.o: $(SRCS) shall be commented or removed.
After having done this way the project can be built under linux or mac and under windows both in Atmel Studio 6.2 and Atmel Studio 7. The latter was not able to build just like it was not possible in linux or mac.
Related
I'm creating a Rules.make file, similar to Linux's 2.0 version, which contains all kinds of targets - including .so files. My goal is to then only need to make minimalistic Makefiles like so:
include $(DIR_TOP)/Rules.make
in the directories that contain any source files I need compiled. The rules also enable me to create targets like so in the "main" Makefile:
something: something_else lib.so
, so that something_else is done first, and then lib.so is built.
Everything has been going smoothly, until I decided to add dependencies to the aforementioned shared library target. I figured something like the following would do the trick:
${DIR_OUT}/%.so: $(shell find $(dir $#) -name *.o)
$(CC) $(CFLAGS) -o $# $(CLIBS) -shared $^
However, to my demise, $(dir $#) apparently expands to $(dir ${DIR_OUT}/%.so), which then results in simply ${DIR_OUT}, which is exactly not what I need. DIR_OUT is simply the top-level directory string, but the target may be invoked from any sub-directories, or simply like target: $(DIR_OUT)/path/to/lib.so. I was hoping that % could match not only file names, but also any directories (which it does), and then have that expanded to $# once it's already decided what the full path is. Doesn't work like that. With this solution, not only the object files I need are included in the building process, but also any other object files that are there in the output folder, and that then produces errors of kind multiple definition of x y z etc.
Is there any other way to get the list of dependencies for the shared library I want to build? Ideally a purely Makefile based solution, but if there isn't one, I'm fond of some bash scripting too.
The solution turns out to be secondary expansion:
.SECONDEXPANSION:
${DIR_OUT}/%.so: $$(shell find $$(dir $$#) -name *.o)
$(CC) $(CFLAGS) -o $# $(CLIBS) -shared $^
I have the following sub-section of makefile that's used to generate the .d files
-include $(wildcard $(patsubst %,$(OBJ_PATH)/%.d,$(basename $(SRCS))))
%.o: %.cpp
#$(CC) -I$(INCLUDE_PATH) $(CFLAGS) $< -MM -MT $(#:.d=.o) > $(OBJ_PATH)/$(notdir $*.d)
${CC} -I$(INCLUDE_PATH) $(CFLAGS) -c $< -o $(OBJ_PATH)/$(notdir $#)
Sometimes when I build the project, I get the following error /bin/sh: /path/to/my/build/dir/file.d: File exists, although .d files does not exist.
Then I keep getting this error, the only way to get rid of it is to remove the whole enclosing directory and use git restore and the system will build successfully.
System info:
git version 2.27.0
GNU Make 4.2.1
Red Hat Enterprise Linux 8.5 (Ootpa)
Free inodes: 426798634
You should remove the # from your line that creates the .d file, so you can see what the command line actually is. It's always a bad idea to add # before your makefile is working 100% correctly. Then you could cut and paste a full failure example into your question, including the command that generated the error message.
Your build lines are not right. During the compilation, you need to use $# not $(OBJ_PATH)/$(notdir $#). It's always wrong to build a file that is not exactly $#.
During the creation of the dependency file $(#:.d=.o) is useless because $# is already set to xxx.o so changing the .d suffix to .o doesn't do anything. You should just use -MT $# here.
You can replace $(OBJ_PATH)/$(notdir $*.d) with the simpler %*.d.
This error is being shown by the shell and there's really no way we can understand what the problem is with the info given. Why would the shell give a "File exists" error when you use ">" to overwrite it?
I have a suspicion that it's not actually this command that is generating that error.
Following is my directory structure
calculator
|
|---src
(multiply.cpp sum.cpp)
|---lib
I am building a static library calc.a using following
ar -rcs calc.a multiply.o sum.o
calc.a is builded in current directory.
I trying calc.a to be put into lib folder not in current directory (i.e. src)
I searched in internet and man page but couldn't find anything.
Any idea?
Since you are using the command line, the easiest way to write the library into the lib directory is to do it explicitly:
ar -rcs lib/libcalc.a multiply.o sum.o
Using a Makefile you can do more sophisticated things, but even then, it boils down to the same thing, e.g. adding the path to the front of the library name.
Since you asked for additional info on your comment, I add here a simple Makefile, which may be helpful to get you started:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=src/main.cpp src/sum.cpp src/multiply.cpp
OBJECTS=$(SOURCES:.cpp=.o)
LIBRARY=lib/libcalc.a
EXECUTABLE=main
all: $(SOURCES) $(LIBRARY) $(EXECUTABLE)
$(LIBRARY): $(OBJECTS)
<tab>mkdir -p lib
<tab>ar -rcs $# $<
$(EXECUTABLE): $(OBJECTS)
<tab>$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
<tab>$(CC) $(CFLAGS) $< -o $#
clean:
<tab>rm -rf main lib/ src/*.o
Important: All <tab>s must be replaced with real tabs, as required by the Makefile syntax!
Makefiles are very very flexible, so they can be very simple and specific to your problem, or as general and/or complex to build many libraries and binaries, based on millions and millions of source code. I suggest you to search for Makefile documentation for more information.
As a final note, I also suggest you to rename your library as 'libcalc.a', since the 'lib' prefix is standard in Unix. Other similar standards apply for other environments.
Using:
Linux as build host (kubuntu 14.04)
Gnu make 3.81
Compiling some C/C++ projects
I have a directory tree like this:
Repository/
Framework/
Source/
Subdir1/
Subdir2/
Subdir3/
et cetera
something more
Projects/
Project1/
Source/
SubdirA/
SubdirB/
SubdirX/
et cetera
Out/ ← subdirs structure below Out/ is for example
Source/
SubdirA/
SubdirB/
SubdirX/
Framework/
Source/
Subdir1/
Subdir2/
Subdir3/
Makefile
Project2/
Source/
...
Out/
...
Makefile
et cetera
The content of the Framework/Source directory is just a connection of some general purpose source files which will be used in a couple of projects. The Framework directory has no own makefile and e.g. won't build a lib. It's just, that the projects uses some of the sourcecode from the Framework directory.
When building Project1, I first cd into the related projects dir and then calling make, e.g.:
cd ~/Repository/Projects/Project1
make
And all build output has to be put into Project1/Out directory.
Below the Out directory, my makefile mirrors the directory hierarchy from the source tree(s).
Within my makefile, I do something like this:
SRCS += $(shell find Source -name "*.c")
SRCS += $(shell find ../../Framework/Source -name "*.c")
BUILDDIR := Out
OBJS = $(addprefix $(BUILDDIR)/, $(addsuffix .o, $(basename $(SRCS))))
$(BUILDDIR)/%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
and this causes the problem that during the pattern rule and the ../.. part, some of the generated object files will be placed outside of my build output directory, e.g.:
gcc -c ../../Framework/Source/*.c -o Out/../../Framework/Source/*.o
My first approach was, to force all source filenames to absolute path names like this:
OBJS = $(addprefix $(BUILDDIR)/, $(addsuffix .o, $(basename $(abspath $(SRCS)))))
This works (even with realpath), but it makes my build output quite ugly because of the long path + filename outputs.
I have a second approach, were I just substitute all ../ parts of the .o files with something like up/ and it looks like this:
OBJS = $(addprefix $(BUILDDIR)/, $(addsuffix .o, $(subst ../,up/,$(basename $(SRCS)))))
but then it unfortunately seems. that I have to duplicate all my pattern rules like:
$(BUILDDIR)/%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
$(BUILDDIR)/up/up/%.o : ../../%.c
$(CC) $(CFLAGS) -c $< -o $#
So, I'm still looking for a slightly nicer solution for this problem.
For some reasons, I have the following restrictions:
no symlinks
no recursive make calls
no use of vpath
no libs
no git submodules ...
Any suggestions for a bit more elegant approach?
Here is the solution:
COLLAPSED_SRC_PREFIXES_IN_BLD := ../../
SRCS += $(shell find Source -name "*.c")
SRCS += $(shell find ../../Framework/Source -name "*.c")
BUILDDIR := Out
.PRECIOUS: %/.
%/.:
mkdir -p $#
define BLD_FROM_TO
$2/%.o: $1%.c Makefile | $$$$(#D)/.
$(CC) $(CFLAGS) $$< $$#
endef
.SECONDEXPANSION:
$(foreach prefix, $(COLLAPSED_SRC_PREFIXES_IN_BLD), $(eval $(call BLD_FROM_TO,$(prefix), $(BUILDDIR))))
$(eval $(call BLD_FROM_TO,, $(BUILDDIR)))
My original answer is preserved below for reference, but the consensus of discussion seems to be that my answer is wrong. When you have been around long enough, as I have, there is a certain "ring of truth" you can hear in certain criticism. One just ignores criticism that lacks the ring of truth, but this criticism has that ring.
The odd thing is that I have been using recursive Make for years in my own work, in a properly refactored manner (so that I do not, in effect, keep multiple instances of more or less the same rule) with the help of include and symlinks to makefiles (and of course by letting my compiler automatically emit the header dependencies), and it all seems to work fine for me. It is not easy to set up, and there is some hassle whenever I open a new source subdirectory; but then I had believed that Make with multiple source directories just wasn't going to be easy to set up, so there I am.
I do not know whether the OP has learned what he had sought to learn today, but I seem to have learned something.
I withdraw my answer. Thank you for having read my answer and having commented on it.
ORIGINAL ANSWER
Makefiles always seem to be hard. There is no definite, unalterable rule, but there are some practices that help.
In general, a file is best made by a makefile, not in the directory of the file's prerequisites, but in the directory in which the file is to be made. Thus, you can use several makefiles, one in each directory in which files are to be made. In your example, for instance, you can put a makefile in the Out/ directory, then move the $(BUILDDIR)/%.o: rule over to that makefile.
If you do not know it already, learn Make's -C option, and start using it extensively and consistently. There is nothing wrong with your cd ~/Repository/Projects/Project1 before make, exactly, unless the reason for the cd is that you didn't think to use -C, instead. Consistent use of -C, both on the command line and within makefile rules, eventually leads you to think in a more productive way about makefiles. It gradually clarifies your perception in the matter, which is good.
Also if you do not know it already, learn the use of Make's $(MAKE), for recursive invocation of Make.
Use $(MAKE) and -C together in your rules.
How exactly you assemble these elements into a solution that works for you depends on the details of what you want to do, but the above advice will tend to keep you from fighting Make's design philosophy. Not fighting will make things easier for you. Since Make's manual explains features, but does not explain the design philosophy underlying the features very well, this is important.
One could write whole chapters in the matter, so I'll stop here; but if there is a specific point upon which you would like me to expand, feel free to let me know.
I'm trying to get the object files and the executable file in different directories. In the root folder there is a obj and exe folder for this, but i have no idea how to get make to run it.
I have tried stuff like:
$(EXEDIR)/sfml-app: $(OBJ)
and
$(OBJDIR)/%.o: %.cpp
but it gives me errors. Can anybody explain me how I can get this to run?
If you want your output to go to another directory, you have to tell make (and the compiler) about it. They won't just guess because you have a variable named OBJDIR! You have to actually make use of it.
Make sure your target names have the directory prefix so make knows where you expect the object files to end up:
OBJ = $(patsubst %.cpp, $(OBJDIR)/%.o, $(SRC))
and make sure you tell the compiler where you want the object files to end up by using the -o flag:
$(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
Similarly, if you want the final output to to into EXEDIR you have to use it both in the makefile and send that value to the linker, again via -o:
all: $(EXEDIR)/sfml-app
$(EXEDIR)/sfml-app: $(OBJ)
$(CXX) -o $# $(OBJ) $(LIBS)