Zmake - Checker Dependencies

Zmake - Checker Dependencies



1 Problem


2 Solution: CheckDeps


The tool CheckDeps_C evaluates C/C++-language files to check its timestamps and dependencies. It is written in Java: package srcJava_Zbnf/org/vishia/checkDeps_C/package-summary. It is able to call as command line invocation from Windows batch-files or a Unix shell script or it is able to call especially in a script of Zmake.

3 Dependency with time stamp comparison of the source with its last time stamp, dependency-file


Last changed: 2012-01

The tool srcJava_Zbnf/org/vishia/checkDeps_C/CheckDependencyFile reads an input text file which contains from the last calling:

If such a list is not available because it is the first build or a build all invocation, the list can be missed. Then no timestamps and dependencies are known.

One after the another source file are processed with this class.

If the dependencies are invalid, the file is checked line per line. Each found #include statement is a dependency for the source file. All depending files are checked in the same way like the source file. It means, a dependency-file may be unchanged because its time stamp is unchanged. Then the known dependencies are used as known for the deeper level and they are checked, but the unchanged file is not processed.

The result of the dependency check is the new dependency situation, which are logged into the dependency file written as output.

If a file is changed or any of its dependency files are changed, the file should be translated (compiled) newly. If any headerfile is changed, but the source file is not changed, the source file should be translated anyway too. To force the translation, its object file or more files are deleted from the object directory.

The deleting of the object file(s) should be done immediately while the inconsitency was found. Because a next processing of the dependency and time-stamp check with the newly written dependency file would not found a changed file. Anytime the comparison between the last and the current situation will be assessed.

A standard maker (GNU, ANT) or a check of existence of the objectfile (in a shell or batch script) will be force the compilation because the object file is removed. If the object file was not removed and the source will be changed but older or any dependency is unkown in the maker script, the maker will not force the compilation. That will be faulty. The deleting of the object helps to educate the correct situation.

4 Using the dependency check in an JZtxtcmd script (Zmake)


Last changed: 2017-08

Usual the dependency checker is used in a subroutine which is invoked with zmake in an JZtxtcmd script. See Zmake.

The head of the zmake sub routine (example):

##The generate-script for a cc-target.
## arg cfgCheckDeps the path to the checkDependency-Config-file. Relativ to srcDir.
## arg srcDir the directory where checkDeps should be operate.
## arg objDir The directory where objects should be found. There "deps.txt" the dependency file is stored.
sub cc(Obj target, String compilerOptions, String cfgCheckDeps = "make/cfgCheckDeps.cfg"
  , String srcDir, String objDir, String toolDir = "")
{ ....

In this example there is a String variable as argument objDir which contains the absolute path to the object directory. A variable srcDir is the path to the source directory, because the currdir of the script may be another one. The argument cfgCheckDeps is presetted with a default value for this example because the translator is part of a source pool with common settings.


 Obj checkDeps = new org.vishia.checkDeps_C.CheckDependencyFile(console, 1);
 checkDeps.readCfgData(cfgCheckDeps, File: &srcDir);
 <+out><:n>checkDeps_C: <&objDir>/deps.txt read successfully<&newline><.+n>

The instance is created and referenced with the Obj checkDeps as a local variable of the JZtxtcmd sub routine. Then some parameter are set, see the operation description in srcJava_Zbnf/org/vishia/checkDeps_C/CheckDependencyFile.

The file which contains currently dependencies deps.txt is located in the object directory. If objects are existent, the file may be usefull to prevent unnecessary compilation. If the object directory is clean, the deps.txt may not existing too. Then no dependencies are known on start.

Check of any file:

 for(input:inputs) {
   ##The checkDeps algorithm itself may be unnecessary for compilation for compilation of all files.
   ##but it creates the obj directory tree which is necessary for compilation.
   ##The checkDeps checks whether the file is changed, delete the obj file on changed file.
   Obj infoDeps = checkDeps.processSrcfile(File: &input.file(), input.localfile());
   <+out><&infoDeps><.+n> ##show state, info and file name on console.

The routine CheckDependencyFile.processSrcfile(...) checks the given source file with all depending files and deletes the existing obj file if the file should be compiled.

Conditional translation:

   String cclabel = jzcmd.nextNr();   ##build a current number for labels.
     REM call the compiler only if the object file is not found.
     if exist <&objDirW>\<&input.localname()>.obj goto :ok<&cclabel>
       echo compile <&input.localfile()>
       <&toolDir>cl.exe <&compilerOptions> <&_includePath> <&outOptions> <&input.absfileW()>  >><&objDirW>\_cc_error.txt
       echo off
       if errorlevel 1 goto :error

The JZtxtcmd zmake subroutine generates a MS-Windows-batch file for this example. The advantages are:

The batchfile contains the checking of existing object file.

Write back dependencies and close:

 ##write back the checked dependencies:

The file given on CheckDependencyFile.readDependencies(sFilePath) is written newly - or firstly if it has not exist before.

Hint: The file contains some designations if some files are newly, see 9 Format of the dependency file. If you invoke the dependency algorithm a second time, there are not newly-designations because the sources are not changed in comparison to the run before. Then you keep a compareable file (text comparison) with the currently dependency situation in respect to an older dependency situation. You can see what has changed.

5 Preventing of compilation though the sources are changed but only changed in comment lines


Last changed: 2012-01

It is the second approach of the CheckDeps_C tool. Some tools generate secondary source files though it is unnecessary. There content is not changed really, only some information written in comments for C-compilation are changed: Time stamp of generation, revision numbers, the person which is logged in in the computer etc. If all that files will be compilated it needs a lot of time.

The CheckDeps_C tool can work with mirrored sources. If the time stamp of a source is changed, it compares line per line with the mirror-source file. If only comment parts are changed, the associated object file is not deleted and the mirror-source is not renewed. A maker can work with the mirror source. Then it does not found a newly source and does not compile.

6 Source pool


Last changed: 2012-01

If the files are compiled with a make file which is generated from any tool, the source files are known in the makefile but the effort to control the CheckDeps_C to check one file after another is to high. Instead one or more directories which contains the source files are parametrized. The srcJava_Zbnf/org/vishia/checkDeps_C/CheckDeps with possible start from command line checks all that source files.

7 System header, control file


Last changed: 2012-01

System header file (stdio.h etc) are not checked because it should be assumed that they are unchanged. On the other hand the system headers may be more complexely especially with conditional compilations (#if defined(...)) as the users file. Therefore it may be an effort to check them.

The control file set with srcJava_Zbnf/org/vishia/checkDeps_C/CheckDependencyFile#readCfgData(java.lang.String) or the argument -cfg:file.cfg from srcJava_Zbnf/org/vishia/checkDeps_C/CheckDeps#main(java.lang.String[]) has the following syntax, example:

-y=D:/Progs/MSC6/act/Microsoft Visual Studio/VC98/Include

which is more formalistic:



{-i=[$(envVar):]includepath }

{ -y=systemincludepath }

8 Conditional dependencies


Last changed: 2017-08

If a user file contains

#ifdef DEFINE
 #include <something.h>

it is not regarded as a special case. All found #include-statements are regarded as dependency.

9 Format of the dependency file


Last changed: 2012-01

The dependency file should not only used for internal storage of the depedency situation. It should be evaluated from the programmers too. Often some unfortunate includes forces unnecarry dependencies and lengthens the make times:

The dependency file should help to investigate whether a source file have to be compiled though the programmer is aware of no guilt. The programmer can detect which included file is to blame to force the compilation.

The dependency file may contain some designations if some files are detect as changed in an dependency run, see $chapter. If you invoke the dependency check a second time, there are not newly-designations because the sources are not changed yet. Then you keep a compareable file (text comparison) with the currently dependency situation in respect to an older dependency situation. You can see what has changed.

The next step may be: carefully change the include situation and the assignment of parts of sources to the header files. That is an important and difficult chapter of programming. If larger software projects are created with the same source pool, it is worthwile to improve that things.

The dependency file shows the following information:

#Special designation characters for change situation in the 2. column:
# ^ Changed timestamp, but no content change outside comments in comparison with the mirror file.
# & Recompile the file and all using files because an included file is changed.
# $ Recompile like &, this file has a changed timestamp, but no content change outside comments too.
# ! This file is changed, force recompile of all including files.

#Include designation character in the 3. column:
# - Direct included.
# + Indirect included in another included file.
# * This file includes the named file directly. It depends on it.
# % This file includes the named file indirectly. It depends on it.

File: 2012-12-25 16:16:46; 1356448606000; D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_Exception.h
!- D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_MemC.h
 - D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_String.h
 + D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/OSAL/os_types_def_common.h
 + D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/includeSpecials/os_Windows_Msc6/os_types_def.h
 .is included in:
 * D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_ThreadContext.h
 * D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/source/Fwc/fw_Exception.c
 * D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/source/Fwc/fw_ExceptionPrintStacktrace.c
 * D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/source/Fwc/fw_MemC.c
 * D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/source/Fwc/fw_formatter.c
 % D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Jc/ObjectJc.h
 % D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Jc/ReflectionJc.h
 % D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/source/Fwc/fw_threadContext.c
 % D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/source/OSAL/Reflection_OSAL.c

File: 2011-03-06 23:20:34; 1299450034000; D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/source/Fwc/fw_Exception.c
&- D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_Exception.h
 - D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_SimpleC.h
&- D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_ThreadContext.h
 - D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/OSAL/os_error.h
!+ D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_MemC.h
 + D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/Fwc/fw_String.h
 + D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/include/OSAL/os_types_def_common.h
 + D:/vishia/Java2C/sf/Java2C/CRuntimeJavalike/includeSpecials/os_Windows_Msc6/os_types_def.h
 .is included in:

It is a part of the file. In this example the headerfile f_MemC.h is changed. On any file it is listed which files includes this file and from which files this file is included.

To detect changed fiels search the character ! in the whole text. It shows the changed files. All depending files are found with them.

Any file can be searched in this text dependency file. Hint: to search a file use the absolute path like it is written here. Use ; D:/path/to/file.c with the colon, then you find the head line of the file, not an include line.