Search code examples
c++buildg++gnu-makeentry-point

main() used as a function and CLI


I have several source files that run together as anonymous publish/subscribe nodes. There is a main function that collects all the nodes and launches them through their start functions.

// main.cpp
#include "nodeA.h"
#include "nodeB.h"

int main(int argc, char *argv[])
{
  /* some argument parsing here */
  start_node_a(argc, argv);
  start_node_b(argc, argv);
}

To make this easier to configure, I'd like to turn the main function into a shell script which launches these nodes. This would mean turning start_node() functions into main() functions so they run from the command line.

#!bin/bash
node_a -args
node_b -different_args

This makes it trickier to run tests, b/c the node main() functions would clash with the test main(), and there is no longer a start_node() function that an automated test could run.

My solution is to wrap the start_node functions in a main function, but this requires some extra boilerplate for each node, and some extra build wizardry to ignore main during test linking but not node building (I'm actually not sure if I can get this to work with gnumake & g++ yet).

// nodeA.cpp  
int main(int argc, char *argv[])
{
  start_node_a(argc, argv);
}

Is there a more elegant way to do this? A method of starting a program from a function call in tests, and starting a program from the command line?

*Note: I've also thought about system calls, but would consider that a worse solution than using the main() wrapper.


Solution

  • Did you consider embedding an interpreter (like Lua or Guile) inside your program? You would then write some script (in Lua, Guile, etc....) to drive your various start_node_a etc...

    So basically, you'll add some application-specific primitives bound and glued to the Lua or the Guile interpreters, and you'll write some Lua or Guile scripts. Both are well documented (here is Lua doc, here is Guile doc) and very used.

    For Lua: create a state using lua_newstate, then use lua_register to add a primitive, luaL_dofile to run a file, luaL_dostring to evaluate a string.

    For Guile: read the Programming Overview

    BTW, I would recommend Guile (LGPL licensed) over Lua (MIT licensed), because I like more Scheme (the Guile language) than the Lua language. In all cases, be cautious about memory management.