</section>
+ <section>
+ <title>Dependencies From External Files: the &ParseDepends;
+ Function</title>
+
+ <para>
+
+ &SCons; has built-in scanners for a number of languages. Sometimes
+ these scanners fail to extract certain implicit dependencies due
+ to limitations of the scanner implementation.
+
+ </para>
+
+ <para>
+
+ The following example illustrates a case where the built-in C
+ scanner is unable to extract the implicit dependency on a header
+ file.
+
+ </para>
+
+ <scons_example name="macroinc">
+ <file name="hello.c" printme="1">
+ #define FOO_HEADER <foo.h>
+ #include FOO_HEADER
+
+ int main() {
+ return FOO;
+ }
+ </file>
+ <file name="SConstruct">
+ Program('hello', 'hello.c', CPPPATH='.')
+ </file>
+ <file name="foo.h">
+ #define FOO 42
+ </file>
+ </scons_example>
+
+ <scons_output example="macroinc" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command output=" [CHANGE CONTENTS OF foo.h]"
+ >edit foo.h</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Apparently, the scanner does not know about the header dependency.
+ Being not a full-fledged C preprocessor, the scanner does not
+ expand the macro.
+
+ </para>
+
+ <para>
+
+ In these cases, you may also use the compiler to extract the
+ implicit dependencies. &ParseDepends; can parse the contents of
+ the compiler output in the style of &Make;, and explicitly
+ establish all of the listed dependencies.
+
+ </para>
+
+ <para>
+
+ The following example uses &ParseDepends; to process a compiler
+ generated dependency file which is generated as a side effect
+ during compilation of the object file:
+
+ </para>
+
+ <!-- XXX The ParseDepends example below fakes proper working by a
+ priori specification of the dependency file. The produced hello.d
+ file is not found (or used) for unknown reasons. -->
+
+ <scons_example name="parsedep">
+ <file name="hello.c">
+ #define FOO_HEADER <foo.h>
+ #include FOO_HEADER
+
+ int main() {
+ return FOO;
+ }
+ </file>
+ <file name="SConstruct" printme="1">
+ obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.')
+ SideEffect('hello.d', obj)
+ ParseDepends('hello.d')
+ Program('hello', obj)
+ </file>
+ <file name="foo.h">
+ #define FOO 42
+ </file>
+ <file name="hello.d">
+ hello.o: hello.c foo.h
+ </file>
+ </scons_example>
+
+ <scons_output example="parsedep" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command output=" [CHANGE CONTENTS OF foo.h]"
+ >edit foo.h</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Parsing dependencies from a compiler-generated
+ <filename>.d</filename> file has a chicken-and-egg problem, that
+ causes unnecessary rebuilds:
+
+ </para>
+
+ <scons_example name="parsedeprebuild">
+ <file name="hello.c">
+ #define FOO_HEADER <foo.h>
+ #include FOO_HEADER
+
+ int main() {
+ return FOO;
+ }
+ </file>
+ <file name="SConstruct">
+ obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.')
+ SideEffect('hello.d', obj)
+ ParseDepends('hello.d')
+ Program('hello', obj)
+ </file>
+ <file name="foo.h">
+ #define FOO 42
+ </file>
+ </scons_example>
+
+ <!--
+ <scons_output example="parsedeprebuild" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c -MD -MF hello.d -I. hello.c
+ cc -o hello hello.o
+ % <userinput>scons -Q --debug=explain</userinput>
+ scons: rebuilding `hello.o' because `foo.h' is a new dependency
+ cc -o hello.o -c -MD -MF hello.d -I. hello.c
+ % <userinput>scons -Q</userinput>
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
+
+ In the first pass, the dependency file is generated while the
+ object file is compiled. At that time, &SCons; does not know about
+ the dependency on <filename>foo.h</filename>. In the second pass,
+ the object file is regenerated because <filename>foo.h</filename>
+ is detected as a new dependency.
+
+ </para>
+
+ <para>
+
+ &ParseDepends; immediately reads the specified file at invocation
+ time and just returns if the file does not exist. A dependency
+ file generated during the build process is not automatically
+ parsed again. Hence, the compiler-extracted dependencies are not
+ stored in the signature database during the same build pass. This
+ limitation of &ParseDepends; leads to unnecessary recompilations.
+ Therefore, &ParseDepends; should only be used if scanners are not
+ available for the employed language or not powerful enough for the
+ specific task.
+
+ </para>
+
+ </section>
+
<section>
<title>Ignoring Dependencies: the &Ignore; Function</title>
</section>
+ <section>
+ <title>Dependencies From External Files: the &ParseDepends;
+ Function</title>
+
+ <para>
+
+ &SCons; has built-in scanners for a number of languages. Sometimes
+ these scanners fail to extract certain implicit dependencies due
+ to limitations of the scanner implementation.
+
+ </para>
+
+ <para>
+
+ The following example illustrates a case where the built-in C
+ scanner is unable to extract the implicit dependency on a header
+ file.
+
+ </para>
+
+ <programlisting>
+ #define FOO_HEADER <foo.h>
+ #include FOO_HEADER
+
+ int main() {
+ return FOO;
+ }
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c -I. hello.c
+ cc -o hello hello.o
+ % <userinput>edit foo.h</userinput>
+ [CHANGE CONTENTS OF foo.h]
+ % <userinput>scons -Q</userinput>
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
+
+ Apparently, the scanner does not know about the header dependency.
+ Being not a full-fledged C preprocessor, the scanner does not
+ expand the macro.
+
+ </para>
+
+ <para>
+
+ In these cases, you may also use the compiler to extract the
+ implicit dependencies. &ParseDepends; can parse the contents of
+ the compiler output in the style of &Make;, and explicitly
+ establish all of the listed dependencies.
+
+ </para>
+
+ <para>
+
+ The following example uses &ParseDepends; to process a compiler
+ generated dependency file which is generated as a side effect
+ during compilation of the object file:
+
+ </para>
+
+ <!-- XXX The ParseDepends example below fakes proper working by a
+ priori specification of the dependency file. The produced hello.d
+ file is not found (or used) for unknown reasons. -->
+
+ <programlisting>
+ obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.')
+ SideEffect('hello.d', obj)
+ ParseDepends('hello.d')
+ Program('hello', obj)
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c -MD -MF hello.d -I. hello.c
+ cc -o hello hello.o
+ % <userinput>edit foo.h</userinput>
+ [CHANGE CONTENTS OF foo.h]
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c -MD -MF hello.d -I. hello.c
+ </screen>
+
+ <para>
+
+ Parsing dependencies from a compiler-generated
+ <filename>.d</filename> file has a chicken-and-egg problem, that
+ causes unnecessary rebuilds:
+
+ </para>
+
+
+
+ <!--
+ <scons_output example="parsedeprebuild" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c -MD -MF hello.d -I. hello.c
+ cc -o hello hello.o
+ % <userinput>scons -Q --debug=explain</userinput>
+ scons: rebuilding `hello.o' because `foo.h' is a new dependency
+ cc -o hello.o -c -MD -MF hello.d -I. hello.c
+ % <userinput>scons -Q</userinput>
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
+
+ In the first pass, the dependency file is generated while the
+ object file is compiled. At that time, &SCons; does not know about
+ the dependency on <filename>foo.h</filename>. In the second pass,
+ the object file is regenerated because <filename>foo.h</filename>
+ is detected as a new dependency.
+
+ </para>
+
+ <para>
+
+ &ParseDepends; immediately reads the specified file at invocation
+ time and just returns if the file does not exist. A dependency
+ file generated during the build process is not automatically
+ parsed again. Hence, the compiler-extracted dependencies are not
+ stored in the signature database during the same build pass. This
+ limitation of &ParseDepends; leads to unnecessary recompilations.
+ Therefore, &ParseDepends; should only be used if scanners are not
+ available for the employed language or not powerful enough for the
+ specific task.
+
+ </para>
+
+ </section>
+
<section>
<title>Ignoring Dependencies: the &Ignore; Function</title>
cc -o hello.o -c hello.c
cc -o hello version.o hello.o
% <userinput>scons -Q</userinput>
- scons: `.' is up to date.
+ cc -o version.o -c version.c
</screen>
</section>