Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing symbol from object file at compile time. For example swapping out main

Tags:

c++

g++

Here's the use case:

I have a .cpp file which has functions implemented in it. For sake of example say it has the following:

[main.cpp]

#include <iostream>

int foo(int);

int foo(int a) {
    return a * a;
}

int main() {
    for (int i = 0; i < 5; i += 1) {
        std::cout << foo(i) << std::endl;
    }

    return 0;
}

I want to perform some amount of automated testing on the function foo in this file but would need to replace out the main() function to do my testing. Preferably I'd like to have a separate file like this that I could link in over top of that one:

[mymain.cpp]

#include <iostream>
#include <cassert>

extern int foo(int);

int main() {
    assert(foo(1) == 1);
    assert(foo(2) == 4);
    assert(foo(0) == 0);
    assert(foo(-2) == 4);        

    return 0;
}

I'd like (if at all possible) to avoid changing the original .cpp file in order to do this -- though this would be my approach if this is not possible:

  1. do a replace for "(\s)main\s*\(" ==> "\1__oldmain\("
  2. compile as usual.

The environment I am targeting is a linux environment with g++.

like image 521
Anthony Sottile Avatar asked Oct 15 '12 22:10

Anthony Sottile


People also ask

What is symbol resolution in linking?

In symbol resolution, weak defined symbols are silently overridden by any global definition of the same name. Another form of simple symbol resolution, interposition, occurs between relocatable objects and shared objects, or between multiple shared objects.

What is linking of object files?

Linking object files to produce an executable The linker combines the contents of one or more object files with selected parts of any required object libraries to produce executable images, partially linked object files, or shared object files.

Are header files compiled?

Header files are not compiled directly, Instead, header files are included into other source files via #include .

How C++ code is compiled?

Each C++ source file needs to be compiled into an object file. The object files resulting from the compilation of multiple source files are then linked into an executable, a shared library, or a static library (the last of these being just an archive of object files).


1 Answers

I hate answering my own question, but here's a solution I ended up finding deep in the man page of g++, I've tested it and it works to what I would want it to...

g++ has the -D flag which allows you to define macros when compiling object files. I know you are thinking "ugh macros" but hear me out... You can use the macro definition to effectively rename a symbol. In my case, I can run the following command to generate an object file of my students code without their main file: g++ -D main=__students_main__ main.cpp -c -o main.nomain.o.

This creates an object file with their int main defined as int __students_main__. Now this isn't necessarily callable directly as they could have defined main as int main(void) or with the various combinations of argc and argv, but it allows me to effectively compile out their function.

The final compile looks like this:

g++ -c -D main=__students_main__ main.cpp -o main.nomain.o
g++ -c mymain.cpp -o mymain.o
g++ main.nomain.o mymain.o -o mymainstudentsfoo.out

For my purposes, I wanted to create a Makefile that would accomplish this automagically (ish) and I feel that is relevant to this discussion so I'll post what I came up with:

HDIR=./ # Not relevant to question, but we have headers in a separate directory
CC=g++
CFLAGS=-I $(HDIR)
NOMAIN=-D main=__student_main__ # The main renaming magic

.SECONDARY: # I forget exactly what this does, I seem to remember it is a hack to prevent deletion of .o files

cpp = $(wildcard *.cpp)
obj = $(patsubst %.cpp,%.o,$(cpp))
objnomain = $(patsubst %.cpp,%.nomain.o,$(cpp))

all: $(obj) $(objnomain)

clean:
        rm -f *.o *.out

%.nomain.o: %.cpp
        $(CC) $(CFLAGS) $(NOMAIN) -c $^ -o $@

%.o: %.cpp
        $(CC) $(CFLAGS) -c $^
like image 198
Anthony Sottile Avatar answered Sep 18 '22 11:09

Anthony Sottile