A simple Cloud9 runner for a C program with multiple files

Last semester I taught a Data Structures course using C.  It was more complicated than I would have liked to create assignments and have students submit solutions.  I never got to what I would consider a good solution, but I’m going to try to record some of the things that helped here while they are still relatively fresh in my mind.

The first thing that I did was try to find a desktop solution that would work well on both Macintoshes and PCs.  This turned out to be untenable, so I moved to looking at cloud solutions.  I found that Cloud9 has a pretty slick setup that works perfectly well out of the box.  Just create a  c/c++ project and start hacking away at their sample main.c.  There is even a fairly decent debugger.  This solution uses cloud 9’s built-in runner that just builds and runs the currently active .c file.

But what happens when I want to create a project that contains multiple files?  The simple runner doesn’t have anything set up to compile more than one C file into an executable.  So, of course, the first pass is to start packing things into header files.  But I spent enough time deep in C compilers and debuggers back in the day that this seemed way to fragile.  And I was trying to establish good practices for the students.

So I took a look at the format of the runner file and found that it was reasonably easy to create a custom runner that builds all of the .c files in a directory into a program and correctly executes the program, even including attaching the debugger.

The documentation for custom runners is pretty sparse, but here’s the link to get you started:  https://docs.c9.io/docs/custom-runners.

Here is how I got past the limitations of a single source (.c) file.

Step 1:  Create a Test Program

Create a directory called “test-compound” and then added two files, main.c and aux.c into the directory.

main.c

#include <stdio.h>

extern void foo();

int main() {
    printf("Entering Main\n");
    foo();
    printf("Extiting Main\n");
    return 0;
}

aux.c

#include <stdio.h>

void foo() {
    printf("Foo is executing\n");
}

Now try running main.c using the C (simple) runner. You should get an error that looks like the following since the target program doesn’t include the code from aux.c.

Running "/home/ubuntu/workspace/test-compound/main.c"
/tmp/ccRmXnkw.o: In function `main':
main.c:(.text+0x14): undefined reference to `foo'
collect2: error: ld returned 1 exit status

Process exited with code: 1

Well, that’s no fun! So let’s see what we can do about it.

Step 2: Create a Custom Runner

You should have a tab in your run configurations (the bottom right view) that is titled test-compound/main.c.  This is where the error text showed up in step 1.  In the upper right side of the tab, you should see the text Runner: C (simple).  This is actually a button, so click on it to reveal a list of all of the built-in runner.  If you scroll all the way to the bottom of that list, you’ll see two additional options: New Runner and Edit Runner.

Choose Edit Runner, which will bring up a file titled C(simple).run that should look something like this:

// This file overrides the built-in C (simple) runner
// For more information see http://docs.c9.io:8080/#!/api/run-method-run
{
  "script": [
    "set -e",
    "if [ \"$debug\" == true ]; then ",
    "    gcc -ggdb3 -O0 -std=c99 $file -o \"$file\".o",
    "    chmod 755 $file.o",
    "    node $HOME/.c9/bin/c9gdbshim.js \"$file.o\" $args",
    "else",
    "    gcc -std=c99 $file -o $file.o",
    "    chmod 755 \"$file.o\"",
    "    \"$file.o\" $args",
    "fi"
  ],
  "info": "Running \"$file\"",
  "debugger": "gdb",
  "$debugDefaultState": false,
  "env": {},
  "selector": "^.*\\.c$"
}

Go to File->Save As and save the file as C (compound).run.  You can just save the file, but if you do this it will override the default behavior once you start modifying it, and that’s not the objective here.  You can choose Show Hidden Files from the directory tree setting (the gear next to the root folder) and open up the .c9->runners folder to see your new runner.

Step 3: Modify Your Runner

// This is a runner for multiple source (.c) files in a directory
// For more information see http://gramamoto.com/a-simple-cloud9-runner-for-a-c-program-with-multiple-files
{
  "script": [
    "set -e",
    "if [ \"$debug\" == true ]; then ",
    "    gcc -ggdb3 -O0 -std=c99  *.c -o \"$file_path/main.out\"",
    "    chmod 755 \"$file_path/main.out\"",
    "    node $HOME/.c9/bin/c9gdbshim.js \"$file_path/main.out\" $args",
    "else",
    "    gcc -std=c99 *.c -o \"$file_path/main.out\"",
    "    chmod 755 \"$file_path/main.out\"",
    "    \"$file_path/main.out\" $args",
    "fi"
  ],
  "info": "Running \"$file\"",
  "debugger": "gdb",
  "$debugDefaultState": false,
  "env": {},
  "selector": "^.*\\.c$"
}

Now when you have a .c file selected in a directory, you can choose Run->Run With->C (compound) and all the source (.c) files in the directory will be built into a single main.out, which will then be run.

Try this on the simple sample application I provided at the beginning of the post.  You should see something like this:

Running "/home/ubuntu/workspace/test-compound/main.c"
Testing...
Entering Main
Foo is executing
Exiting Main


Process exited with code: 0

And we have a successful run of a c program with two source files.  For homework assignments, you could provide a header file and a main.c with tests and have the student add additional source file(s) to complete the solution.

How to Remove Client Secrets from Source Code: Part I (the code part)

I wanted to share the music4dance code with a potential employer, but I didn’t want to share all of the various keys and secrets that I use to shared login services, music search services and such.  Since I hadn’t previously shared the code with anyone other than people that I would trust to share the keys as well, I have been pretty sloppy with just checking them in with source code.  This is particularly nasty since that meant that if I actually wanted to share the git repo, I would not only have to clean up the code, but I’d have to change every one of the client secrets and passwords.

It’s pretty well documented in a number of places that a reasonable way to do this is to save such sensitive information in the environment and load it at runtime.  That way it will never get checked into the source code.  The problem that I haven’t seen a nice solution to online is dealing with a whole bunch of these at the same time.  There are two parts to this, the changing of the source code and setting up the environment on all the machines that need it.

The documented way to load an environment variable is straightforward:

public string MyKey => Environment.GetEnvironmentVariable("mykey");

And if there’s some possibility that the property is read multiple times (and generally there is), you can easily cache the variable (I love some of these new C# syntax enhancements).

public string MyKey => _myKey ?? 
    (_myKey = Environment.GetEnvironmentVariable("mykey"));
Private string _myKey;

Now, I’m doing this in a dozen or so places in my code, and almost all of them conform to a pattern where I am storing a pair of values.  Either client key and secret or username and password.  So I threw together a little class to handle this.

public abstract class CoreAuthentication
{
    protected abstract string Client { get; }
    public string ClientId => _clientId ?? 
        (_clientId = Environment.GetEnvironmentVariable(Client + "-client-id"));
    public string ClientSecret => _clientSecret ?? 
        (_clientSecret = Environment.GetEnvironmentVariable(Client + "-client-secret"));

    private string _clientId;
    private string _clientSecret;
}

The idea for this is that I had a number of specific authorization handlers for each of the music services that would extend this class and override the Client property to let CoreAuthentication know what environment variable to read.

Then for the simpler cases where I just needed to grab the info and use it to an OWIN security provider, I created a generic subclass that just takes the client name that I use as the base of the environment variable name.

public class EnvAuthentication : CoreAuthentication
{
    public EnvAuthentication(string client)
    {
        Client = client;
    }

    protected override string Client { get; }
}

I use the EnvAuthentication class in my startup authorization like so:

var fbenv = new EnvAuthentication("fb");
var fb = new FacebookAuthenticationOptions
{
    AppId = fbenv.ClientId, 
    AppSecret = fbenv.ClientSecret
};

Not rocket science, but a somewhat cleaner solution than having Environment.GetEnvironmentVariable calls all over my code.

I’ll attack the problem of loading up all of those environment variables next time. Especially the case of batch loading into the azure app service, which I found particularly vexing.