Inform 7 v10's Compile to C question

Even without the Parser/World Model, there’s a lot of stuff built into Basic Inform: you have all the infrastructure for relations, tables, rules, rulebooks, activities, and generating adaptive text. For instance, you could write this:

Datum is a kind of object.
The plural of datum is data.

Surveys is a plural-named datum.
Graph is a datum.

To demonstrate is a verb.

To begin:
  say "[The surveys] [demonstrate].";
  now the story tense is future tense;
  say "[The graph] [demonstrate]."

And there’s no attempt to strip unused functions. And the way that Inter is translated into C seems to work a lot like: imagine what glulx bytecode the I6 compiler would generate for this bit of Inter, and then generate C that imitates each of those bytecodes in turn.

With gcc, the program above compiled to a 985K binary, but letting gcc optimize for size and strip unused stuff, it got down to 384K.

gcc -lm -I"inform7/Tangled"  -Os -flto -fdata-sections -ffunction-sections basic.c -o basic  -Wl,--gc-sections
2 Likes

The C output is a great start, but it does need some work. I do think, it could be a lot better. But i understand the first priority is always to get it working.

It looks @inform7tips is no longer on twitter. I was able to retrieve these helpful threads from the Wayback Machine (original thread on compiling Inform to C, another wrinkle on C only sections), and I can’t find a whole lot of info on this topic, so I hope it’s okay if I take the liberty of reposting them here for posterity. (I’m not using the blockquote tag because it gives the regular text and code the same background color, which is harder to read, but, to be clear, everything below was written by @Zed.)


Compiling I7 v10 to C

I’ve mentioned that one can compile Inform7 v10 to C instead of Inform 6. Here’s how. (This one won’t be of much interest to people not using inform7 on the command-line.)

inform7 -format=C -internal "$INFORM7DIR/Internal" -transient /tmp -o project.c -source project.i7

If you omit -o project.c it’ll automatically write a .c file with the basename of the source file to the same directory as the source file.

-transient is specified because if you don’t have a -transient or -external specified, inform7 will create $HOME/Inform if it doesn’t already exist so it has somewhere to create a Telemetry dir. The Project Index isn’t created if you use -source.

Then, for gcc users:

gcc -I "$INFORM7DIR/Tangled" -lm project.c -o project

gcc needs to be able to find inform7_clib.h, -I is one easy way to do it. The math library is needed, hence -lm. If you omit -o project, the executable ends up called a.out.

If you’re familiar with I7’s kits (née the I6 Template Layer) you know that one gets different code depending on whether you’re targeting Z-code or Glulx. Compiling to C means you get Glulx-flavored output with a word size of 4 (i.e., 32-bit); Z-code flavored is not an option. (But there will never be a Glulx interpreter involved, of course.)

I7’s own “Miniglk” is built in. According to the documentation, one could build it with one’s own choice of Glk implementation with some effort, but I haven’t tried that yet.

Instead of specifying the source file with -source, one can use -project, but when you use a project you can’t specify -o. The output file will always be auto.inf in its usual location under project.inform/Build, despite being a C file. So…

inform7 -no-progress -no-census-update -format=C -internal $INFORM7DIR/Internal -transient /tmp -project project.inform

Since gcc normally uses the file suffix to determine the source format, you’ll need to add -x c to tell it this is C.

gcc -I "$INFORM7DIR/Tangled" -lm -x c -o project project.inform/Build/auto.inf

And in either the source or project case one can specify an External directory with -external if there are extensions there you want the compilation to have access to.)

Some references:

inform7 command-line usage

target virtual machines


C only sections

Know how you can put (for glulx only) or (for Z-machine only) at the end of a heading for that passage to be included only when compiling to that target? Well, here’s an undocumented feature: you can also say (not for glulx) or (not for Z-machine).

Given just two choices, this would seem like a candidate for the most trivial factoid I’ve tweeted, but here’s another undocumented feature in v10: you can also say (for C only) or (not for C).

I’ve described compiling to C as being “glulx-flavored”. One of the ramifications of that is that when compiling to C, (for glulx only) passages are included, and, of course (not for glulx) passages are excluded.

So how could you include something when compiling to I6 that would be compiled to glulx but exclude it when compiling to C? You could do, e.g.,

Chapter Foo (for glulx only)

Section Bar (not for C)

[code]

But, of course, these conditionals are more of interest when writing extensions than for an individual game. For your own game, you know what target you want and probably aren’t worried about maintaining the ability to switch among three different choices. So if you did want to have differences between C and ulx, unless you also wanted to be able to compile to the z-machine, you could get by with just (not for C) and (not for glulx).

3 Likes

You can find Inform7tips on Mastodon:

Inform 7 Tips (@inform7tips@mastodon.gamedev.place) - Gamedev Mastodon

1 Like

Following the above instructions, I’ve managed to successfully compile a test project. I did find one issue: the -lm flag has to come after the C source file. The command I used was:

gcc -I /usr/share/inform7-ide/Miscellany project.c -lm -o project

yeah, editing the collective inform7tips twitter and mastodon archives into something useful is on the (very long) list. Thanks for recovering these bits.

2 Likes