Replacing a character from an object file at compile time. For example, replacing the main

A use case is used here:

I have a .cpp file that has the functions implemented in it. For example, let's say that 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 do some automatic testing of the foo function in this file, but I will need to replace the main() function to do my testing. Preferably, I would like to have a separate file similar to this, which I could link on top of this:

[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 would like (if at all possible) to avoid modifying the source .cpp file to do this, although that would be my approach if this is not possible:

  • replace for "(\s)main\s*\(" ==> "\1__oldmain\("
  • as usual.

The environment I'm aiming for is a linux environment with g ++.

+4
source share
4 answers

I hate answering my question, but here is a solution that I found deep in the g++ man page, I tested it and it works on what I want ...

g++ has the -D flag, which allows you to define macros when compiling object files. I know what you think of poppies, but listen to me ... You can use macro definition to effectively rename a character. In my case, I can run the following command to create an object file for my student code without their main file: g++ -D main=__students_main__ main.cpp -c -o main.nomain.o .

Creates an object file with its int main , defined as int __students_main__ . Now this may not necessarily be called directly, since they could define main as int main(void) or with various combinations of argc and argv , but this allows me to efficiently compile their function.

The final compiler is as follows:

 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 execute this automatically (ish), and I believe this is relevant to this discussion, so I will 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 $^ 
+3
source

You can use the --allow-multiple-definition option for ld *:

[ac]

 #include <stdio.h> int foo() { return 3; } int bar() { return 4; } int main(void) { printf("foo: %i\n", foo()); return 0; } 

[bc]

 #include <stdio.h> int bar(); int main(void) { printf("bar: %i\n", bar()); return 0; } 

[shell]

 $ gcc -Wall -c ac $ gcc -Wall -c bc $ gcc -Wl,--allow-multiple-definition ao bo -o foobar && foobar foo: 3 $ gcc -Wl,--allow-multiple-definition bo ao -o foobar && foobar bar: 4 

*: At one's own risk:)

+1
source

I support the djechlin proposal. But if you want something quick and dirty, here is a suggestion:

You can define a macro and wrap your function calls as follows:

 #ifdef MYTESTING #define ASSERTEQUAL(fn, parm, ret) \ assert( fn ( parm ) == ret ) #else #define ASSERTEQUAL(fn, parm, ret) fn ( parm ) #endif 

And in your main function, use the following call, ASSERTEQUAL (foo, i, 4);

Use the following compilation flag to enable custom macro behavior.

 -DMYTESTING 

Hope this helps!

0
source

This cannot be done at compile time. You need a connection time solution. (Or use a preprocessor.)

In any case, you probably want to separate the "regular" and "test" characters and selectively include their source files in the compilation or object files when linking. *

Although I would prefer to use the unit testing framework or at least NDEBUG for assert() s.

* eg:.

 #ifdef TESTING #include "main-testing.c" #else #include "main.c" #endif 

or

 ifdef TESTING OBJS += main-testing.o else OBJS += main.o endif 

Update: I just realized that you are looking for a solution where main-testing.o main will override main.o (right?). I will save this answer and add another option for the override solution.

0
source

Source: https://habr.com/ru/post/1439936/


All Articles