F.A.Q.
Build Questions
Q. I'm getting the following error:
Warning: need to build target mytarget.exe but it has no commands.
What could be wrong?
A. Make sure that you have an action which takes mytarget.exe as one of the elements in the first argument passed to it. Confirm this by printing out the arguments to the action right before you call it:
rule MakeProgram TARGET
{
echo $(TARGET) ;
MakeProgramAction $(TARGET) ;
}
action MakeProgramAction TARGET
{%
# ... action script goes here ...
%}
Another common error is to forget that you must pass in the argument to the action by evaluating the variable, instead of passing in the variable name directly. For example this would be wrong:
MakeProgramAction TARGET ; # wrong: argument is not expanded.... MakeProgramAction $(TARGET) ; # probably what you want.
Q. KJam will sometimes build a target whose dependents have not changed. What could be wrong?
A. You probably have a timestamp race condition. That is a file x is depending on a target y whose timestamp changes during the build and where the first time you build y is older than x, such that a rebuild of x is not necessary. The next time, since y has been updated, x is older than y and so x gets rebuilt, even though no files have changed.
This can happen when a rule has more than one target. For example a certain rule has targets A and B. And you have another target C which depends on B. If you ask KJam to build A and C, B will get built as a side effect. The next time you issue the same build command, A may need to get rebuilt because during the last build the timestamp of B which it depends on was updated. To help diagnose this situation KJam will always issue a warning when a target is built as a side-effect of building another target.
It can also happen when files get updated as a side effect of a build. For example if you have a log file which gets updated by some targets, and is depended on by others. One run of the build updates the log file, the next time you run the build the targets which depend on the log file get rebuilt.
It can happen with directory targets. The directory's timestamp will be modified every time a file is added or removed from the directory. This may cause targets which depend on this directory to need to update during a subsequent build. To solve this problem make sure to flag directory targets with the noupdate keyword. Noupdate causes KJam to ignore a target's real timestamp, and to consider the target to be old. With directories you normally only care to make sure they exist.
Q. KJam is building certain targets multiple times unncessarily. What could be wrong?
A. This can happen when in your jamfiles you invoke the same build action more than once, with the same argument list, but the arguments in a different order. For many build actions argument order doesn't matter, and so it may seem that KJam's insistence on building multiple times is unnecessary. But for some build actions order of arguments does matter. For example if the action was to concatenate files. KJam doesn't know what the build action intentions are so it assumes that it must call the action multiple times with the arguments in each given order.
To diagnose this problem, add a print statement to the build rule which is building more times than you wish and confirm that it is being called with the same arguments multiple times from different places. If this is the case, you can solve this problem one of two ways. Either sort the arguments to the build rule so that the rule is invoked in the same order each time using the T variable expansion modifier, or label the action as piecemeal, together or updated. When an action is labeled this way KJam can safely conclude that argument order is not important.
Q. Sometimes KJam seems to skip necessary targets, causing the build to fail. What could be wrong?
A. You may have a condition where a build action unexpectedly removes a target which exists at the start of the build. For example some tools, when they encounter an error will delete the output file that they are processing. Sometimes this happens when a build action purposely deletes temporary targets.
This can cause build system errors where KJam appears to skip building necessary targets, and the build fails later when that target is needed. KJam determines the total list of files which need updating in an early scanning phase. If during the later updating phase files are deleted, KJam's list of files to build is not updated. KJam will unexpectedly ( but correctly ) skip building the deleted files.
To diagnose this problem, run KJam with the -d search option and see if KJam is finding the file that it is refusing to build during its first pass. If the file is found during the scanning phase, but is missing by the time it is needed, then check your actions for commands which may be deleting this file. If the file is indeed missing at the start, but KJam is refusing to build it, then check that the dependencies between these files are set correctly using the -d fate option.
Q. Sometimes KJam seems to hang. What could be wrong?
A. The most common cause is that one of the build steps has hung for some reason.
First look at the load on the machine. If the processor load is high then probably your build steps are just taking a long time. Since KJam builds multiple steps at the same time it is possible that individual steps may seem to take longer than normal. Overall parallel builds are faster, even on a single processor machine because when one process is blocked waiting on resources like the disk, other build steps can be running.
If the processor load is low, then one of the following things may have happened:
1. Some tools in your build process may not be designed to handle building in parallel. If they try to access a file which is locked by another process they may hang waiting for the lock to be released. Try running the build with -j1, such that KJam will not launch any processes in parallel. Consider updating the tool to make it check that all file accesses take into account the posibility of a locked file. The KJam tool itself always checks if a file handle is locked before using it and should not hang for this reason.
2. A file that one of the build tools depends on is locked by a process which is hung. This especially common after terminating a build prematurely ( will ctrl-c or a signal ). Check the process list for zombie process which don't use cpu and also never seem to terminate. Look for instances of the compiler or linker. Some compilers spawn many processes when building and may not terminate all of them properly when terminated. If your clean step is unable to remove certain files, it is likely that there is a hung process locking them. Manually terminate such processes.
3. If your build environment calls KJam recursively, look for instances of KJam which are hung. This can happen when the build jobs that they spawn hang. It is sometimes easier to just terminate those instances of KJam than to look for the job which they are waiting on.
4. If the hang only happens in when using KJam in network mode, then consider that one of your build steps may be waiting for user input. Most build tools will never request interactive user input. However, there are cases where an unexpected error may cause a tool to pop up an error dialog window on a remote machine. This can happen on Windows for example if a program fails to load a required .dll. In this case check to make sure that all build tools are properly configured on all the build servers.
Q. In network mode, when I call another version of KJam to build a subdirectory it hangs. Why?
A.Check to make sure that there are enough copies of KJam server running on the network and that they are configured to run multiple jobs each. When a new copy of KJam in network mode is launched as a build action it will keep a build job locked as busy while it waits for any build jobs from its spawned version of KJam to terminate. The spawned version of KJam will wait until one of the build servers is not busy. But since the parent version is waiting for the child to finish, the server will never become available. A deadlock results.
To cure this condition make sure that there are enough build jobs available by making sure that every KJam server is configured to host more than one job ( by default KJam is configured to host up to 4 simultaneous jobs ) or that there are multiple build servers available on the network.
Q. In network mode, why is KJam unable to connect to any build servers?
A. There are many things which could cause KJam to have trouble connecting to build servers. First make sure networking between the two machines is working properly testing other network services such as pinging the remote machine or attempting a file transfer. KJam pings machines on the local network before checking to see if there is a KJam build server running on that machine. Most systems will respond to ping packets by default. It is possible that the remote machines have been specially configured to ignore ping packets. In this case KJam would fail to connect to them. By default KJam build servers listen for connections on port 2297. Make sure that this port is not being blocked by a firewall. It is also possible that the KJam build servers on your network have been configured to listen on a different port.
Q. Why is debugging output is badly formatted and hard to read?
A. The debugging output is formatted for shells with at least 160 columns. This can be achieved with almost all modern shells.
Windows uses cmd.exe as its default shell. This shell is extremely primitive and limited to only 80 columns. It is highly recommended that Windows users upgrade their shell to something more powerful. There are many options. Consider for example installing cygwin and running rxvt and bash.
Another option would be to pipe the debugging output to a file and review it later using a text editor.
Q. My jamfile has a build action which creates a directory, and another build action which generates its output into that directory. When I run KJam, the build action fails saying the directory is missing. Yet when I look in the file system, the directory has indeed been created. Whats wrong?
A. By default KJam is multi-threaded. This means that KJam probably ran the directory creation action and the build action at the same time. When the build action started up the directory had not yet been created. Even though the build action failed, KJam will continue to process all build actions which have already started. This is why the directory was created correctly - just too late.
To solve this problem you need to make sure that the generated file depends on the directory in which it will get written. This is not necessary in build systems where the directory can be expected to always exist before the build is run. This is true for example in build environments where the object directories are under source code control and are populated when the project is updated. For build environments where the directories are generated by KJam, you must specify a dependency using the depends keyword.
You can diagnose prolems like this by checking the dependency graph with the option -d fate. You can see exactly what threads get spawned and when by running with -d thread.
Q. KJam dependency scanning does not evaluate macros. Some of my #include statements are are controlled by conditional macros. How do I deal with this?
A. KJam's dependency scanning uses a highly optimized regular expression scanner. This runs much faster than a general purpose c or c++ parser which evaluates macros. This can result in KJam finding dependencies on header files which are not actually included because of conditional macros. These header files may not actually exist on the current platform. For example when building on linux, you may be including windows headers which don't exist on linux machines. This will cause the build to fail because the headers are not found. To solve this problem label such header targets with the nocare keyword. This will cause the build to continue even if these headers are not found ( the desired behavior ).
The combination of extra dependencies and the nocare keyword effectively solves this problem. The extra dependencies are usually benign. The conditionally included header files are typically system headers which change rarely. At worst the extra dependencies will occasionally case KJam to perform an unneccesary build step when a header is changed which is not actually included.
If a search path is set incorrectly it is possible to have missing dependencies. Suppose you have a file which is included, and is also labeled with nocare. If the search path is set incorrectly that file might not be found. Because it is labeled nocare no error is reported and the build continues as normal. This is effectively a missing dependency. When developing jamfiles which use the keyword nocare it is recommended that the build be run at least once with the -d search command line option, and the list of files not found should be carefully checked by hand to make sure only the expected files are not found.
Q. One of my build tools is unstable and will occasionally crash, causing the build action to terminate with an error. This breaks my build process. Is there anything I can do?
A. You can instruct KJam to try to run certain unstable actions more than once until they succeed with the retry action modifier. If you set retry KJam will retry the action an unlimited number of times. If you give it a number KJam will attempt to run that action the given number of times before giving up and reporting an error. This can get your build process around some occasionally unstable tools.
Be aware that KJam cannot tell when a tool terminated abnormally due to a crash versus terminating abnormally due to a normal compiler error. This means that build actions labeled retry which hit a compiler error will be run multiple times uncessarily. For build actions which can terminate with compiler errors you may want to write your jamfiles such that the retry option is only applied to the action during special automated builds ( like in an autobuild checkin verification system ). There is no downside to setting retry on actions which should always succeed unless there is a crash.
Q. One of my build tools is unstable and will occasionally hang, causing the build to hang. This breaks my build process. Is there anything I can do?
A. You can instruct KJam to allow certain actions to run no longer than a given amount of time with the timeout modifier. timeout is normally followed by a number which is the timeout limit in seconds. The timeout limit should be fairly generous because it is possible for an action which is not hung to sometimes take longer than normal if the build system is heavily loaded or if it is waiting on a locked file system resource.
It is often useful to combine timeout with retry. This way if an action hangs, KJam will terminate it and then try to run it again. Judicious use of timeout and retry can greatly increase the robustness of automated build processes, even when using tools which crash or hang unexpectedly.
Q. Some of my SEARCH and LOCATE variables appear to be being ignored. What could be wrong?
A. First make sure that these variables are being set correctly using the -d varSet option, and that they are in fact not being used to bind your targets using the -d search option. If you see the variable being set correctly, and yet not being used by during binding then your problem may be that you are using the :F option and it is binding your target before the SEARCH and LOCATE variables are set.
Normally targets are only bound to files and directories during the binding phase. The :F option will force binding for that target to happen in the middle of the parsing phase. This can be extremely useful, but you have to be aware of where the SEARCH and LOCATE variables are being set. If they are set after the :F is evaluated then they will not be used for binding. When a later attempt at binding these targets happens, such as during the normal binding phase, KJam will see that the target is already bound and will not rebind it.
To solve this problem make sure that any :F expansion modifiers are applied only after SEARCH or LOCATE are set. In addition if SEARCH and LOCATE are set on a target those values will only get used in the binding phase. You can achieve a similar effect as LOCATE on when using the :F modifier by creating a local LOCATE variable. The :F option is always safe inside an action because they are run after the binding phase in the update phase.
Q. I though KJam was supposed to generate dependencies automatically. Why do I have to use depends and includes?
A. depends and includes can be used to generate dependencies between specific targets manually, but this is not their main use. For most build systems you will never need to do this.
depends and includes are mostly used to set up dependency relationships between categories of objects in rules. For example for telling KJam that all .obj files depend on some matching .src file. They are also used by the $(HDR_SCAN) rule to scan source files for dependencies using regular expressions. KJam uses this information so that it can figure out the dependencies between targets automatically. Once you set this up in the rules of your jambase file, you will not have to worry about setting dependencies between individual targets in your jamfiles.
Q. What is the difference between depends and includes?
A. depends A : B C creates a dependency relationship. It says that target A needs to be updated if sources B or C change.
includes A : B C says that dependents of A are also dependents of B and C. If B or C change then all targets that depend on A need to be updated. Think of it as a way of forwarding dependency relationships up the dependency graph toward the final target.
Q. I am using the built-in jambase. What must I do to create a new top level build rule like StaticLibrary? I want the clean and all targets to be updated as well.
A. You need to create the top level rule, and one action for each supported platform. For example lets create a new type called DataFile. For simplicity its action is just to copy a file from one place to another:
rule DataFile TARGET : SOURCE
{
if ( $(AUTOALL) == true ) depends all : $(TARGET) ;
LOCATE on $(TARGET) = $(BIN_DIR) ;
CreateDirectory $(TARGET_DIR) ;
CleanTarget $(TARGET) : $(BIN_DIR) ;
depends $(TARGET) : $(SOURCE) $(BIN_DIR) ;
DataFileAction $(TARGET) : $(SOURCE) ;
}
action quietly DataFileAction TARGET : SOURCE
{%
echo "Making Data $(SOURCE) -> $(TARGET)"
cp $(SOURCE) $(TARGET)
%}
Include the rule and action at the top of your jamfile, or insert it into the built-in jambase files using the -P and -X options. If the actions have any platform specific commands you will need to build one action for each supported platform and put the action in the platform specific jambase file.
Now you can use the new rule like any of the other built-in rules:
DataFile test : test ;
Q. I labeled an action as piecemeal 1. I call that action with two long lists of matched sources and targets, like this:
myAction file1.obj file2.obj file3.obj : file1.src file2.src file3.src ;
A. You need to indicate to KJam that the list of sources matches the list of targets one for one by labelling the action with the keyword updated.
This keyword tells KJam that in a single call to a particular action it only needs to update the targets whose corresponding sources are out of date. It also indicates that there is a one to one mapping between the list of targets and sources. In this case when it splits up an action labeled piecemeal it will split both the targets and sources.
Without the updated keyword KJam has no way of knowing that the list of targets and sources matches one for one, so it will call the action for any target with the list of sources exactly as you passed them in.
Q. I'm getting warnings like this one:
Warning: Target main.obj will be built as a side effect of building another target.
A. This warning means that the build rules are organized in such a way that KJam finds that it must build targets which do not seem to be necessary. For example, suppose you have a program called a.exe, that depends only on a.obj, which in turn depends on a.cpp. Now suppose that the rule to make a.obj also builds another target b.obj. Since b.obj is not a dependent of a.exe, KJam would warn you that this unecessary target is will be built. This can only happen when you create build actions which have multiple simultaneous targets, either because the first argument to the action has multiple targets listed, or because that action is labeled as together.
There are three possible actions you should consider:
1. If the side effect target really is a dependent of some other necessary target then you need to fix the dependencies. Use -d depends and -d fate to check the dependency graph.
2. If the side effect target is not a dependent, then consider calling the build action for this target alone without other simultaneous targets, or remove the together keyword from its build action.
3. Sometimes multiple targets must be built at the same time. For example tools like yacc, bison and flex will generate both source and header files each time they run. Or there may be performance advantages to building targets in a batch, such as when using compilers like MSVC. In these cases you may determine that the side effect warning is ok, and take no action.
Q. My build has link and clean commands that are more than 8k characters long. Does KJam support long build commands? What is the maximum length of command lines in KJam actions?
A. The simple answer, avoiding a bunch of detail, is 32k on Windows, and unlimited on most Posix platforms.
On Posix platforms like Linux and OsX, the APIs that spawn new processes don't have specific limits on the length of the command lines. How long the command lines can actually be will depend on the implementation, but in practice on these platforms command lengths are long enough as to be practically unlimited.
Windows is more limited. The Windows APIs that spawn new programs are limited to 32767 bytes. Unlike most build tools KJam uses its own internal shell. It calls these APIs directly and supports full 32k commands. This command limit applies only to the parts of a command line which actually must spawn a process to run. For example in the case of two commands connected by a pipe ( | ), each command can be 32k long. There is no limit to the number of pipes. Many commands are built in to the shell ( such as cp, mv, rm, mkdir etc. ) and since they do not spawn new processes those commands also have no length limit.
Most Windows build systems ( such as Gnu Make, Scons, Jam etc. ) spawn commands using an external shell, usually the windows shell program cmd.exe. This program is limited to a maximum command length of 8192 bytes. If KJam is specially configured to use cmd.exe ( using the JAM_SHELL variable ), then KJam will also be limited to 8k command lines.
Windows can still run 16-bit DOS programs in an emulation mode. These old programs rely on an obsolete process spawning API which limits their command lines to 127 bytes. In the unlikely event that you are using one of these old programs, and issue commands longer than 127 bytes, KJam will warn you about this issue.
Q. Does KJam support DJGPP?
A. Yes. DJGPP binaries are 16-bit DOS binaries. All 16-bit DOS binaries are limited to short command lines under 126 bytes, which is too short for many build steps. In order to work around this limitation DJGPP binaries can use 'response files'. Pipe all the arguments to the program into a file, and then pass the filename to the DJGPP binary as a single command line argument preceded by an @. The file should have a unique name, incorporating the name of the target being built for example, so that one build thread does not overwrite the response file of another. Once the command has terminated the response file should be deleted. For example a DJGPP build action might look like this:
echo $(CXXOPTS) $(SOURCE) -o $(TARGET) > $(TARGET).opts $(CXX) \@$(TARGET).opts rm $(TARGET).opts
Language Syntax Questions
Q. How do I concatenate strings with spaces between them?
A. Suppose you have a variable holding a set of strings:
LIST = one two three ;To concatenate them with spaces between the elements do:
CONCAT = "$(LIST:J=' ')" ;This will not work:
CONCAT = $(LIST:J=" ") ;The reason it doesn't work is because the Jam language parser interprets this as two ill-formed names: $(LIST:J=" and "). Surrounding the name with quote marks causes the parser to treat it as one name.
Q. When environment variables are converted into Jam variables they are split into pieces on whitespace boundaries. This can be a problem for windows file paths with spaces in them. How do I deal with this?
A. Variables that end in path are split on ; on Windows and on : on Linux. So you can get around most of these problems by using a variable that ends in path. If this is not possible, then you can reconstruct the original path using the J variable expansion modifier, and then resplit the path on ; or : boundaries.
MSVCDIR = "$(MSVCDIR:J=' 'O=;)" ;
Q. The use of ; is not consistent. You need it in the rules, but not in the actions. Why?
A. The action scripts are not part of the KJam language. Except for one pass of variable substitution, the body of an action is passed to a command shell, and uses command shell syntax. Depending on what shell you are using the syntax would change. The default is to use the KJam built-in shell, which follows sh syntax as closely as possible. The user can plug in their own shell if they want ( dos cmd.exe, bash ). Many shells allow ; as a command separator. In this context processing of the ; is entirely under the control of the given shell.
Q. It seems like when a variable doesn't exist and you use it in an echo statement, nothing prints out.
echo "test $(BADVAR)" ;
Prints nothing at all (not even 'test')
A. Yet the following works as you expected:
echo test $(BADVAR) ;
Here is what is happening. When you quote a string you are creating a single token which gets expanded. When a token value is expanded, the value
becomes the product of all the variable expansions that it is made of. If one of the variables is empty, then the product is empty. This useful feature
is what allows you do things like:
/I$(INCLUDE_DIRS) /L$(LIB_DIRS)When you don't put quotes around it, then you are echoing out two separate tokens, delimited by whitespace, which is what you expect.
Q. I have a list of include directories, and I want to transform them into a series of include flags to pass to MSVC like so:
/I "C:/Program Files/one/include" /I "C:/Program Files/two/include" ;How do I write an expression that does this?
A. It is tricky to make variable expansions that use the quote character or whitespace, because these characters have a special meaning to the KJam parser. The trick to using whitepace in an expansion is to put quote marks around the whole expansion so that the KJam language parser treats the whole thing as a single expression. The trick to using " is to escape it by prefixing a backslash. Like so:
DIRS = "C:/Program Files/one/include" "C:/Program Files/two/include" ;
FLAGS = "/I \"$(DIRS)\"" ;
Q. How can I make one of the arguments to a variable expansion modifier to be a literal \" ?
A. It can be tricky to make variable modifier arguments which use \ and " characters because these have a special meaning to the KJam parser, and also to the regular expression parser. Do it like this:
# the argument to the second modifier 0, is \"
TEST = "foo\bar" "goo\bar" ;
print $(TEST:N="\\"0="@(\)\"") ;
# prints foo\"bar goo\"bar
Q. Variable modifier arguments seems to treat the \ character inconsistently. Arguments to N, X and I treat \ as an escape character,
and arguments to 0-9 do not. For example:
TEST = foo.bar goo.bar ;
print $(TEST:N="\."0="\.") ;
# prints foo\.bar goo\.bar
# shouldn't this print foo.bar goo.bar?
Shouldn't the \ in the 0 argument be removed the way it is in the argument to N?
A. Some modifiers, like N, X and I interpret their arguments as regular expressions, and others like 0-9 interpret them as literal strings, which are used exactly as they are specified. Regular expressions have many characters which have special meanings, like . * [ ] ^ & etc. To use these characters as literal characters without special meaning they must be prefixed with the \ escape character. Non regular expression arguments, do no special processing of their arguments and so will treat the \ character as just another regular character. The only exception to this is the use of \ before " or '. This is interpreted by the KJam language parser as an escaped " or ' in all cases.
Q. On Windows the output of KJam is wrapped neatly to the width of the shell, but on Linux, the output seems to wrap at 80 columns no matter how wide I make my shell. Whats wrong?
A. Most shells which support resizing, like bash, set an environment variable COLUMNS to the width of the shell. The built-in KJam jamfiles use this variable to set the text wrapping feature to the shell width. If KJam is unable to find the COLUMNS environment variable, it will set the wrapping feature to a default width of 80 columns.
On Windows environment variables set in the user shell are passed to any process spawned from that shell. So on Windows, the output text wrapping feature will work automatically when you resize your shell ( if you are using a shell which supports horizontal resizing - not cmd.exe )
On Linux, by default, processes do not get local environment variables. So on Linux you have to specifically tell KJam the width of the shell. You can do this one of two ways. You can either export the COLUMNS environment variable, by typing export COLUMNS at your shell prompt, or you can pass the value of the COLUMNS environment variable to KJam on its command line ( e.g. kjam -s COLUMNS=$COLUMNS ... ). It is convenient to create an alias that does this for you automatically whenever you run KJam.