BCC64X Parallel Compilation

From RAD Studio

Go Up to BCC64X

Using bcc64x --jobs with MAKE

The Modern C++ compiler bcc64x can compile several source files in parallel within a single invocation using the --jobs option (--jobs=0 uses all available cores). To take advantage of this from a Borland makefile, MAKE must hand the compiler several source files on one command line instead of invoking the compiler once per file.

MAKE does this through command batching: the braces { } in a rule command mark the portion of the command that varies from file to file. MAKE collects the text inside the braces for every matching target, then runs the command once, splicing all collected file names together. That single command line is what enables --jobs to compile the files concurrently.

Makefile Example

The example below is a Borland makefile using bcc64x with parallel compilation (--jobs):

CC   = bcc64x.exe
LINK = bcc64x.exe

!ifndef NO_PARALLEL
PARALLEL_OPTS = --jobs=0
!else
PARALLEL_OPTS =
!endif

.nosilent

OBJS = file_001.o file_002.o

Batching only combines objects built in one MAKE run, so build the aggregate target (myapp.exe) rather than an individual object. As usual, the first target is the default goal when you run MAKE with no target arguments, so it is listed first here.

myapp.exe: $(OBJS)
    $(LINK) -tC $(OBJS) -o myapp.exe

file_001.o: file_001.cpp file_001.h
file_002.o: file_002.cpp file_002.h

.cpp -> .o inference rule.

The compile line is the ONLY command in the rule, and everything except the file list ({$? }) is identical for every file. Both conditions are required for batching to work.

.cpp.o:
    $(CC) $(PARALLEL_OPTS) -output-dir . -tC -c {$? }

clean:
    del $(OBJS)
    del $(OBJS:.o=.d)
    del myapp.exe

Build it with the following code:

make -f makefile.bmak

MAKE issues a single command such as:

bcc64x.exe --jobs=0 -output-dir . -tC -c file_001.cpp file_002.cpp

and bcc64x compiler the two sources in parallel.

Rules and limitations of { } batching

Batching is subject to several constraints. If any of them is violated, MAKE silently falls back to invoking the compiler once per file, and no parallelism occurs—the build still succeeds; it is just not batched.

The batched command must be the only command in the rule

An inference rule that contains `{ }` batching may contain nothing but the compiler invocation. Any additional command line — for example, a directory check such as:

  .cpp.o:
       if not exist "$(INTERMEDIATE)" mkdir "$(INTERMEDIATE)"   # breaks batching
       $(CC) --jobs=0 ... -c {$? }

causes the pending batch to be flushed before the next file is added, so each file is compiled by itself. Move setup steps like this out of the rule (for example, into a separate prerequisite target that runs once).

Only the text inside `{ }` may vary between files

Everything before the `{` and after the `}` must be byte-for-byte identical for every target that uses the rule. In particular, do not place the target name in the command (for example `-o $@` or a per-file output name). Let the compiler derive output names, e.g. with `-output-dir`. If the text outside the braces differs, that file is compiled separately.

Use exactly one `{ }` region per command

MAKE uses the first `{` and the first `}`. Empty braces `{}`, a `}` that appears before `{`, or a second brace pair are not treated as batching.

Batches are limited by the command-buffer size

When the accumulated file list would exceed the command buffer, MAKE flushes the current batch and starts a new one, so a very large project may be compiled in several batched invocations rather than one. Long command lines (`-l`, a 4 KB / 8191-character buffer) are on by default in current MAKE, so most projects batch into a single invocation. Only if long command lines are turned off (`-l-`) does the smaller 255-character buffer apply, which splits large file lists into several batches. You normally don't need to change this; just don't pass `-l-` when you want maximum batching.

The `-u` switch (and the `!` command modifier) disable batching

Unbatch mode runs every command individually and defeats `--jobs` batching.

See Also