Large C/C++ projects consist of thousands of files. For example, the Linux kernel
has about 20,000 files. If you are developing such project and want
to rebuild it after a small change - say, a one line fix -
there are two options.
Full rebuild (Clean and Build action). It is slower,
but guarantees a consistent build result.
Incremental rebuild (Build action). It is faster,
but will it correctly rebuild everything that should be rebuilt?
The major problem with incremental rebuild is presence of #include
directives that include one file's content into another file. Modification
of the included file should be treated as modification of all files that
include it. Indirect includes (A includes B, B includes C => A includes C)
make the problem even harder.
NetBeans IDE 6.5 supports automatic checking of file dependencies and
does its best to make incremental rebuild work correctly. If you change
a header file that is included into some of your source files and then
click Build, NetBeans will rebuild only those
parts of the project that really depend on the changed header.
This feature saves time and guarantees consistent build results.
Enabling Dependency Checking
There is a checkbox in the Project Properties dialog box that controls dependency checking
for each particular project. You may want to ensure that it's enabled:
There is also a checkbox in the Options window that sets the default state
of the dependency checking feature for newly created projects:
Notes
Automatic dependency checking works for managed C/C++ projects.
For projects created from existing sources you have to rely on dependency
checking logic (if any) in existing Makefile.
Dependency checking requires support from your tool collection
(make and compilers). It has been tested with the Sun tool collection
and GNU tool collections including Cygwin and MinGW.
Dependency checking works when Sun compilers are used together with
Sun make, and GNU compilers with GNU make. Mixing
Sun make with GNU compilers and vice versa is not supported.
The rest of the article is for those advanced users who
want to know what happens under the IDE's hood.
Build Process (make and makefiles)
The build process of every C/C++ project in NetBeans is described
in a Makefile, a file of special format understood by
make utility. When you build or clean your project from the GUI,
NetBeans just invokes make, which executes the Makefile. This
allows you to easily build your project outside of the IDE: just cd
to your project directory and type make help to get instructions.
Makefiles used by NetBeans for a C/C++ project are shown
below.
The master Makefile is generated once and you can edit it manually. Makefiles in nbproject directory are not meant for manual
editing; they are updated automatically by the IDE.
Makefile-CONF.mk in the picture means that there are
as many files as you have project configurations,
e.g. Makefile-Release.mk, Makefile-Debug.mk, etc.
In the case of a managed project, NetBeans generates all the makefiles itself
and inserts proper instructions for dependency checking. In the case of
a project created from existing sources, dependency checking will
work only if existing Makefile contains such instructions,
because the NetBeans IDE doesn't change the existing Makefile.
Dependency Generation Basics
If you want make to check included file dependencies during build
then you have to insert dependency information into the Makefile.
Unfortunately there is no portable way to do this for all makes
and compilers. First, you should detect which make is running,
and then generate corresponding dependency checking instructions.
Sun's make has a very simple solution. A special .KEEP_STATE:
rule in Makefile instructs make to query compiler about included
file dependencies and store them in a temporary file. Next time
the project is rebuilt, make loads that temporary file,
analyzes dependencies stored there, and determines which headers changed
and which object files should be recompiled.
For GNU make the solution is more complex. You have to explicitly
ask compiler to generate dependency information and then explicitly
include it into the Makefile. The idea is to pass special flags
to the compiler, so that compiler will generate dependency information
for each compiled source file. Next time the project is rebuilt, dependency
information is collected and included into the Makefile.
Implementation
The following code is added to nbproject/Makefile-impl.mk.
It detects which make is running and puts corresponding
dependency checking code into file .dep.inc. GNU make is detected
by the presence of MAKE_VERSION variable. If MAKE_VERSION
is not set, then Sun's make-specific instructions are generated.
# dependency checking support
.depcheck-impl:
@echo "# This code depends on make tool being used" >.dep.inc
@if [ -n "${MAKE_VERSION}" ]; then \
echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES}))" >>.dep.inc; \
echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \
echo "include \$${DEPFILES}" >>.dep.inc; \
echo "endif" >>.dep.inc; \
else \
echo ".KEEP_STATE:" >>.dep.inc; \
echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \
fi
The following code is added to nbproject/Makefile-${CONF}.mk.
It instructs make to read previously generated .dep.inc
and execute instructions from it.
# Enable dependency checking
.dep.inc: .depcheck-impl
include .dep.inc
The rule .dep.inc: .depcheck-impl is added to prevent build
failure when .dep.inc does not exist. There is only one case
when it happens: when you compile single file from the Projects window.
In this case make executes file nbproject/Makefile-${CONF}.mk
directly.