Environment variable to configure the location of the cpp source files - c++

I am writing a cpp library for myself and I have put the deader files in a folder <root>/include and the cpp files in <root>/src folder. To add my include path to the environment, I have appended <root>/include to CPLUS_INCLUDE_PATH. Now, the problem I am facing is that I am getting an error during the linking step because the linker is unable to find the implementation of my class. Is there any environment variable where I can mention this like the way I have done for the header files?

You cannot do that. The linker needs compiled code and cannot deal with your source files. What you can do is to write a Makefile that will compile all your source files in the /src folder and link compiled files to the target. Example of a Makefile doing this:
ROOT = YOUR_ROOT_DIRECTORY_HERE
LDFLAGS = OPTIONS_TO_LINKER_HERE
CPPFLAGS = OPTIONS_TO_COMPILER_HERE
SRC=$(wildcard $(ROOT)/src/*.cpp)
your_app: $(SRC)
g++ $(CPPFLAGS) $(LDFLAGS) -o $# $^
Compile your application using: make your_app, or make.

Related

Link .h files and .c files from different directory using makefile

I'm trying to compile a program called um from a current folder with um.c
and include some external implementations. The .h files are in one directory but the .c files implementing these .h files are in a different directory. Below is my makefile. It seems that the compiler knows where to look for the .h file. However, the linker fails and produces the error:
ld: symbol(s) not found for architecture x86_64
clang: fatal error: linker command failed with exit code 1
Makefile:
# define the C compiler to use
CC = gcc
# define any compile-time flags
CFLAGS = -g -O -Wall -Wextra -Werror -Wfatal-errors -std=c99 -pedantic
# define any directories containing header files other than /usr/include
INCLUDES = -I/Users/nguyenmanhduc/Documents/C\ library/cii/include
# define library paths in addition to /usr/lib
LFLAGS = -L/Users/nguyenmanhduc/Documents/C\ library/cii/src
# define any libraries to link into executable:
LIBS = -lm
# define the C source files
SRCS = um.c
# define the C object files
OBJS = $(SRCS:.c=.o)
# define the executable file
MAIN = um
.PHONY: depend clean
all: $(MAIN)
#echo Simple compiler named um has been compiled
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $#
clean:
$(RM) *.o *~ $(MAIN)
depend: $(SRCS)
makedepend $(INCLUDES) $^
This question might seem weird because I have little experience with makefile but is there a way that I can link .h and .c files in different folders using makefile.
Thanks!
The problem here is not that your additional .c files are in different directories: it's that you didn't tell your Makefile that they exist at all!
Here's where you list the source inputs (I guess you didn't see the comment?):
# define the C source files
SRCS = um.c
Add the other .c files whose compiled .os are what you want to link.
For example:
# define the C source files
SRCS = um.c ../wot.c ../hah/lol.c
There is no hard and fast rule but, the way you've constructed this Makefile, those relative paths should resolve just fine.
You don't link .c files, you link .o files.
You appear to be stating is that some of your .c files are in a different directory.
No matter, you have to explicitly list those .c files, in your makefile, just like you are listing the .c files in the directory with the makefile. You have to compile the .c files in a different directory, and then link them, just like you're compiling and linking the .c files in the same directory as the makefile. They're not going to compile themselves.
Another approach would be to have a separate makefile in that other directory, that compiles and builds an archive library, and then in this directory link with that archive library.

Working with Makefile, source generators and generating dependencies with gcc

In the project I have:
main.cpp
template.sth
much more
For each .cpp file I am generating .o file.
Thanks to that I could write simple rule for all .o targets (simplified, a little bit pseudcode version for more clarity):
OBJS = #list of all .o files needed
%.o: %.cpp
g++ -MM -MF %.d -MP -MT %.o %.cpp
g++ -c -o %.o %.cpp
Then I am including all existing .d files, so after each generation I am refreshing dependencies.
It worked unless I had template.sth. This file contains some template for generating h files and cpp files.
When one file, i.e. main.cpp includes file generated from template.sth (lets say gen.h):
Instruction generating .d file doesn't work, because gen.h is missing:
fatal error: gen.h: No such file or directory include "gen.h"
Even if these instructions would work there is a problem with my "workflow". Untill now I could generate .d file for next make. It worked, because adding new dependencies require to change one of current dependecnies. So after adding one .o is rebuilding and new .d is generated. Now I need to detect that before making .o I need to generate gen.h from template.sth.
Is there any way to do it automatically? Problem 1. could be solved if there is some way to tell g++ that if some .h file is missing it can just add it to dependencies.
After solving problem 1. executing make multiple times (I think twice is always enough) end up with built project (first make would generate dependencies files, then second make sees that main.cpp depends on gen.h, gen.h is missing and there is instruction how to create gen.h so it will create gen.h before building main.o).
If it can't be done somehow automatically, how can it be solved? Can I write in Makefile instructions which will build all generated files before any other or I need to manually add this generated file as dependencies in all .o instructions?
UPDATE:
After few changes, with -MG flag g++ generates correct files even for gen.h. I can build my project now with two make commands.
First one will create correct .d files and break, because gen.h is missing.
Second one will have .d files ready, so it will generate gen.h before building main.o, so building main.o will be successful.
Is there a way to generate .d file and then use it, before generating .o?
You need to add dependencies for the generated files:
gen.h: template.sth
...command to create gen.h from template.sth
If you have lots of generated files, you might want a way of creating those dependencies automatically, which would depend on how you are generating them.
In addition, you want to generate the .d files independently from the .o files and use the -MG flag while generating them to ignore missing files:
%.d: %.cpp
g++ -MM -MF $# -MP -MG $<
-include $(OBJS:.o=.d)
This way, the first time you run make, it will generate the .d files with the dependencies and then reread them and recompute all the dependencies before trying to build anything else.

Changing file paths in included makefile

I have project and few subproject
Some of subprojects are very independent. They works without any knowledge about whole project, they are build differently and have its own Makefile. This Makefile is located in subproject root dir.
Whole subproject is built to single object file.
Is there any way to properly include such object file to main Makefile? By "properly" I mean preserving all dependencies and building this file using method in subproject Makefile.
I tried to create rule for building this object file:
path_to_subproject/some_object.o:
$(MAKE) -C path_to_subproject
But that way I cannot preserve any dependencies.
What I need is to convert all relative path in subproject Makefile and include it to main Makefile.
Another way could be telling main Makefile that some_object.o is built using different Makefile, so make should use it to check dependencies etc.
Suppose the makefile in subproject/ looks like this:
some_object.o: some_source.cc some_header.h
$(CXX) -c $< -o $# -I.
You can modify it like so:
HERE:=/full/path/to/subproject
$(HERE)/some_object.o: $(HERE)/some_source.cc $(HERE)/some_header.h
$(CXX) -c $< -o $# -I$(HERE)
This will act the same as the original when used by itself (except that you can no longer make some_object.o from subproject/, you must make /full/path/to/subproject/some_object.o-- that can be fixed, but you must make a design decision or two).
Now you can add a line to the bottom of the master makefile:
include path_to_subproject/Makefile
and then the master makefile can use that object:
some_executable: local_object.o /full/path/to/subproject/some_object.o
whatever
More sophisticated variations are possible, once you have this working.

Example makefile for building simple c project recompiling when headers change

Does anyone have a complete makefile that can do the following:
Rebuilds the project if a HEADER file changes
The cpp files are listed in the makefile
The header files are NOT listed in the makefile
The header files are allowed to have different names than the cpp files
Some of the cpp files do not have header files
I have seen instructions for figuring out how to make the make tool figure out header dependencies, but none of these instructions provide anything remotely resembling a working example. A simple example would be as follows: main.cpp C1.cpp C1.h C2.cpp C2.h
CXX = g++
OBJECTS := main.o C1.o C2.o
all: $(OBJECTS)
%.o : %.cpp
$(CXX) $(CPPFLAGS) -Wall -MMD -c $< -o $#
-include *.d
EDIT: As TobySpeight points out, this won't work if you build an object file, rename or delete one of the prerequisite source or header files, then try to rebuild the object file; the .d file will still require the missing file, and the build will fail. I neglected to include lines to deal with that case:
%.h: ;
%.cpp: ;
(This is effective, but crude. The more precise approach is to put some sed commands in the %.o rule, so as to add specific null rules to the .d file, one for each prerequisite, but the sed commands are ugly, and the approach above is good enough for almost all cases.)
You can also use CMake for this. Everything you need to write is:
add_executable (exec main.cpp C1.cpp C2.cpp)

Object files generation and best practices for linking using makefiles - C++

Background
I am just getting started with C++ programming on LINUX. In my last question, I asked about best practices of using makefiles for a big application. "SO" users suggested to read Miller's paper on recursive makefiles and avoid makefile recursion (I was using recursive makefiles).
I have followed miller and created a makefile like the below. Following is the project structure
root
...makefile
...main.cpp
...foo
......foo.cpp
......foo.h
......module.mk
My makefile looks like the below
#Main makefile which does the build
CFLAGS =
CC = g++
PROG = fooexe
#each module will append the source files to here
SRC :=
#including the description
include foo/module.mk
OBJ := $(patsubst %.cpp, %.o, $(filter %.cpp,$(SRC))) main.o
#linking the program
fooexe: $(OBJ)
$(CC) -o $(PROG) $(OBJ)
%.o:
$(CC) -c $(SRC)
main.o:
$(CC) -c main.cpp
depend:
makedepend -- $(CFLAGS) -- $(SRC)
.PHONY:clean
clean:
rm -f *.o
Here is the module.mk in foo directory.
SRC += foo/foo.cpp
When I run make -n, I get the following output.
g++ -c foo/foo.cpp
g++ -c main.cpp
g++ -o fooexe foo/foo.o main.o
Questions
Where should I create the object(.o) files? All object files in a single directory or each object files in it's own modules directory? I mean which is the best place to generate foo.o? Is it in foo directory or the root (My example generates in the root)?
In the provided example, g++ -c foo/foo.cpp command generates the .o file in the root directory. But when linking(g++ -o fooexe foo/foo.o main.o) it is looking for the foo/foo.o. How can I correct this?
Any help would be great
Where should I create the object(.o) files? All object files in a single directory or each object files in it's own modules directory? I mean which is the best place to generate foo.o? Is it in foo directory or the root (My example generates in the root)?
I find it easier for investigating failed builds to localize object files in a separate directory under the module level directory.
foo
|_ build
|_ src
Depending on the size of the project, these object files are grouped to form a component at a higher level and so on. All components go to a main build directory which is where the main application can be run from (has all dependent libraries etc).
In the provided example, g++ -c foo/foo.cpp command generates the .o file in the root directory. But when linking(g++ -o fooexe foo/foo.o main.o) it is looking for the foo/foo.o. How can I correct this?
Use:
g++ -o fooexe foo.o main.o
+1 for SCons.
I am using SCons, too. It scans the dependencies for you and it only rebuilds when source has changed as it uses cryptographic hash sums instead of timestamps.
In my SCons build the objects live in parallel directories to the source (to enable multiple builds like combinations of 32bit and 64bit, release and debug):
src
.build
linux
i686
debug
release
x86_64
debug
release
With regards to object and other generated interim files, I put these in a directory completely separate from the sources (I.e. under a directory that is excluded from backup and revision control). It may be slightly more bother to setup in projects or makefiles, but it saves time packaging up sources, and it is easier to have clean backups and revision control.
I create a subdirectory structure for the object files that matches the subdirectory structure for sources. Typically I have a separate subdirectory for each of my libraries and programs.
Additionally I also use multiple compilers (and versions) and multiple operating systems, so I will reproduce the object file directory structure under a directory for each of these compilers (which have newer versions of the standard and vendor libraries) to prevent object files with mismatched included header file versions.
The best thing you can do for yourself is to use something better than Make. SCons is my tool of choice on POSIX systems. Boost also has a build tool that is very flexible, but I had a hard time wrapping my head around it.
Oh, and if you want to use make, go ahead and build recursive makefiles. It really isn't that big a deal. I worked on a gigantic project using tons of recursive makefiles over the last three years, and it worked just fine.