SHTOOL-SCPP.TMP(1)
π SHTOOL-SCPP.TMP(1) β the GNU shtool C source file pre-processor π
okay bestie, sit down, hydrate, because we're talking about shtool-scpp, aka the GNU shtool C source file pre-processor, and it's genuinely one of the most underrated little tools in the whole shtool lineup. no cap. π«Ά
β¨ SYNOPSIS β¨
shtool scpp [-v|--verbose] [-p|--preserve] [-f|--filter filter]
[-o|--output ofile] [-t|--template tfile] [-M|--mark mark] [-D|--define
dname] [-C|--class cname] file [file ...]
πΈ DESCRIPTION πΈ
so basically this command is an extra ANSI C source file pre-processor, and its whole job is helping you share cpp(1) code segments, internal variables and internal functions across files. the origin story? writing libraries in ANSI C, babes. when you're doing that, you usually have a common shared internal header file that carries information between the library source files. it's giving β¨collaborationβ¨.
the way it works is: it parses special constructs inside files, generates a few things out of those constructs, and inserts them at the position mark in tfile by writing the output to ofile. and the best part β the input files are never touched or modified. not even a little. instead, the constructs get removed later by the cpp(1) phase of the build process. the only prerequisite is that every file has a "#include ""ofile""" at the top. yes that's the exact literal text, don't come for me, I'm just the messenger. π
this command provides the following features:
First up, it avoids namespace pollution and reduces prototyping efforts for internal symbols by recognizing functions and variables that are defined with the storage class identifier cname. for instance, if cname is intern, then a function "intern void *foobar(int quux)" in one of the files gets translated into both a "#define foobar __foobar" and an "extern void *foobar(int quux);" in ofile. and that's not all β a global "#define" cname "/**/" is also created in ofile, so the compiler will silently ignore this extra storage class identifier. iconic behaviour honestly. π
Second, your library source files usually want to share "typedef"s, "#define"s, etc. across the source file boundaries. to pull that off you can either place this stuff manually into tfile, or you can use scpp's second feature: all code in files encapsulated with "#if "dname ... "#endif" is automatically copied to ofile. plus a global "#define" dname 0 is also created in ofile, so the compiler silently skips these parts β because it already found them in the header, duh. π
π OPTIONS π
the following command line options are available, and yes we're doing all of them:
-v,--verboseβ display some processing information. it's chatty, we love a chatty queen. π£οΈ-p,--preserveβ preservesofileindependent of the generated#linelines. this is useful for Makefiles if the real contents ofofilewill not change, just line numbers. default is to overwrite. so if you don't want it steamrolled, use this. π₯-f,--filterfilter β apply one or more pre-processingsed(1)filter commands (usually of type"s/.../.../") to each input file before their input is parsed. this option can occur multiple times, so stack 'em up bestie. π§-o,--outputofile β output file name. default is"lib.h".-t,--templatetfile β template file name. default is"lib.h.in".-M,--markmark β mark to be replaced by generated constructs. default is"%%MARK%%".-D,--definedname β FIXME. default is"cpp". (yes, FIXME. we're keeping it real, the docs literally say that. π)-C,--classcname β FIXME. default is"intern". (same energy. π)
π EXAMPLE π
here's a whole little universe of an example, and honestly? she ate.
# Makefile
SRCS=foo_bar.c foo_quux.c
foo_p.h: foo_p.h.in
shtool scpp -o foo_p.h -t foo_p.h.in \
-M %%MARK%% -D cpp -C intern $(SRCS)
/* foo_p.h.in */
#ifndef FOO_P_H
#define FOO_P_H
%%MARK%%
#endif /* FOO_P_H */
/* foo_bar.c */
#include "foo_p.h"
#if cpp
#define OURS_INIT 4711
#endif
intern int ours;
static int myone = 0815;
intern int bar(void)
{
ours += myone;
}
/* foo_quux.c */
#include "foo_p.h"
int main(int argc, char *argv[])
{
int i;
ours = OURS_INIT
for (i = 0; i < 10; i++) {
bar();
printf("ours now %d\n", ours);
}
return 0;
}
see how %%MARK%% is just sitting there in the template waiting to be replaced? main character energy. β
π¦ HISTORY π¦
the GNU shtool scpp command was originally written by Ralf S. Engelschall <rse@engelschall.com> in 1999 for GNU shtool. it was prompted by the need to have a pre-processing facility in the GNU pth project. a legend, truly. π
π« SEE ALSO π«
and that's the whole page bestie!! this one's from shtool 2.0.8, dated 18-Jul-2008 β yes, she's an elder but she still slays π β¨ mwah, go pre-process something gorgeous ππ«Ά
π¦ where this page comes from
- debian bookworm: shtool 2.0.8-10 Β· GPL-2.0-or-later
- debian trixie: shtool 2.0.8-10 Β· GPL-2.0-or-later
- ubuntu jammy: shtool 2.0.8-10 Β· GPL-2.0-or-later
- ubuntu noble: shtool 2.0.8-10 Β· GPL-2.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms