Search code examples
calgorithmmakefileflexibility

How to build a flexible code hierarchy


So, I have an algorithm, composed of parameters A, B, C and D, and operations X, Y and Z. The objective is to write code that will test all combinations (within a certain range) of A, B, C and D, and possibly change the operations X, Y or Z.

This would be simple if it was just a matter of placing variables within a certain range. But since I want to also change operators, it is not as simple.

My idea is to write the code that would cover all combinations. For example, lets consider that there are only two parameters (A and B) and that the range is the same for both: [1,2], integers. The code would build (and if possible, execute) 4 different executables, corresponding to use the algorithm with:

A = 1, B = 1
A = 1, B = 2
A = 2, B = 1
A = 2, B = 2

Now adding the operators. For example, we pick the previous example and add operation X, where it can be [+,-]. The resulting set is:

A = 1, B = 1, X = +
A = 1, B = 2, X = -
A = 2, B = 1, X = +
A = 2, B = 2, X = -
A = 1, B = 1, X = -
A = 1, B = 2, X = +
A = 2, B = 1, X = -
A = 2, B = 2, X = +

(I hope I wrote all combinations)

Anyway, I believe it is possible to build such structure using a makefile, where it attributes values to constants of a code written in C. I am not sure that is possible to change the operators in such way. I was thinking of using a makefile for simplicity. It is always possible to write code that generates code, but seems quite exaggerated for the case.

Perhaps it would create a tree structure? I'm not sure if it is beneficial to have (and picking the first example):

|--Makefile
|--A1
|   |--B1
|   |   |--a.out
|   |--B2
|       |--a.out
|--A2
    |--B1
    |  |--a.out
    |--B2
        |--a.out

Using make I believe I can add extra variables/operators to the code and rebuild all the tests easily. Also, does this structure allow the use of the jobs functionality of make in order to have multiple threads running?

Thanks


Solution

  • Method I've used in the past:

    You can write a shell script to define a macro and then compile the program. Using this method, you can write just one source file and compile multiple programs. Example program that performs some operation on two numbers passed in via command line args:

    #include <stdio.h>
    #include <stdlib.h>
    int main(int argc, char** argv[]){
        if (argc != 3){ //takes just 2 numbers (for example purposes)
            fprintf(stderr, "Usage: prog num1 num2\n");
            return 1;
        }
        int a = (int)strtol(argv[1], (char**)NULL, 10);
        int b = (int)strtol(argv[2], (char**)NULL, 10);
        int c = a MySpecialOperation b;
        printf("%d %s %d = %d\n", a, MySpecialOperationText, b, c);
        return 0;
    }
    

    You will quickly notice that MySpecialOperation and MySpecialOperationText are undefined. This is intentional. (Also the program assumes that the command line args are valid.)

    Now let's say you want 4 programs that perform the 4 basic arithmetic operations. Write a script to compile your program (this is in BASh):

    echo \#define MySpecialOperation \+ > tmp.c
    echo \#define MySpecialOperationText \"plus\" >> tmp.c
    cat myprogram.c >> tmp.c
    gcc tmp.c -o addition_prog
    echo \#define MySpecialOperation \- > tmp.c
    echo \#define MySpecialOperationText \"minus\" >> tmp.c
    cat myprogram.c >> tmp.c
    gcc tmp.c -o subtraction_prog
    echo \#define MySpecialOperation \* > tmp.c
    echo \#define MySpecialOperationText \"times\" >> tmp.c
    cat myprogram.c >> tmp.c
    gcc tmp.c -o multiplication_prog
    echo \#define MySpecialOperation \/ > tmp.c
    echo \#define MySpecialOperationText \"divided by\" >> tmp.c
    cat myprogram.c >> tmp.c
    gcc tmp.c -o division_prog
    rm tmp.c
    

    This script automatically creates a new file, writes the preprocessor statement #define to it, defining the previously undefined variables, then appends the original source file to it. Now, the compiler will replace MySpecialOperation with the operation (+,-,*, or /) and MySpecialOperationText with the appropriate word, and the code will compile and perform that operation.