简体   繁体   中英

Selecting implementations of C++ functions using the linker

I would like to test C++ functions in a piece of code by swapping them one by one for ones that are known to work in a working context, where the swapping is done using the linker. (I use C++ with GCC under linux.) Unfortunately I do not know enough about how to drive the linker to know how to do this or even if it is possible.

For me, the main reason is to test students' code against a teacher's model solution, though I can imagine plenty of other cases where such methods may be of interest. Note that the students' source code is available and can be compiled in any way I like, but this source cannot be edited. However, the teacher's code can be modified as needed.

There follows a simple example that shows the idea.

Here is, the teacher's code, in which the functions can call each other in ways similar to that shown. All functions here are assumed to meet their specifications exactly.

#include <iostream>

using namespace std;

// model teacher program : main calls g which calls f

int f(int x) {
  cout << "in teacher-f(" << x << ")" << endl;
  return 46;
}

int g(int x) {
  cout << "in teacher-g(" << x << ")" << endl;
  int y = f(x);
  cout << "f(" << x << ") returned " << y << endl;  
  return 91;  
}

int main() {
  cout << "in teacher-main()" << endl;
  int x = 2;
  int y = g(x);
  cout << "g(" << x << ") returned " << y <<  endl;  
}

A typical student's code, attempting to meet the same specifications, to be tested. In my case a "main", several #includes, and "using namespace std;" would be expected.

#include <iostream>

using namespace std;

// model student program : main calls g which calls f

int f(int x) {
  cout << "in student-f(" << x << ")" << endl;
  return 27;
}

int g(int x) {
  cout << "in student-g(" << x << ")" << endl;
  int y = f(x);
  cout << "f(" << x << ") returned " << y << endl;  
  return 82;  
}

int main() {
  cout << "in student-main()" << endl;
  int x = 4;
  int y = g(x);
  cout << "g(" << x << ") returned " << y <<  endl;  
  return 0;
}

I want to swap each of the teacher's functions one by one to test each student function individually.

Here is one attempt, in this case testing the student's g()

g++ -c student.cpp
# (this makes student.o)
# strip f() and main() from student.o:
strip -N main -N _Z1fi student.o

# similarly for teacher, but stripping g
g++ -c teacher.cpp
strip -N _Z1gi teacher.o
g++ -o final teacher.o student.o
./final

and the result I would expect is

in teacher-main()
in student-g(2)
in teacher-f(2)
f(2) returned 46
g(4) returned 82

unfortunately, I get:

strip: not stripping symbol `_Z1fi' because it is named in a relocation

I have tried doing something similar with .so libraries instead. The error message to strip disappears, but unfortunately this time the teacher main calls the teacher g that I had tried to remove.

g++ -shared -fPIC -o student.so student.cpp
g++ -shared -fPIC -o teacher.so teacher.cpp 
strip -N main -N _Z1fi student.so
strip -N _Z1gi  teacher.so
g++ -o final teacher.so student.so
./final

giving

in teacher-main()
in teacher-g(2)
in teacher-f(2)
f(2) returned 46
g(2) returned 91

Any suggestions? Is this even possible? If not, is there any way round to do the same thing? As said I cannot edit student.cpp, but I could #include it from other source code.

Thanks Richard

This somewhat violates your requirements, but I would suggest you to change the expected form of student's code. Do not require them to code main , or ask then to code main in a separate compilation unit, or just ask them to rename their main to say main_ before submission. Or just add #define main main_ to the top of student's code after the submission before the compilation; for simple tasks this will be enough.

After that, you do not need to strip anything from compiled code. Just place all your functions to namespace teacher , write your own main that will do all needed work, and link all code together. Change and recompile your code to call teacher::f for your function, or ::f for the student's function.

I think the only possible solution is to separate it to two files:

1st file should be common for teacher and student and may contain both main and f + forward declaration for g :

common file: (common.cpp)

#include <iostream>    
using namespace std;
int g(int x) ;

int f(int x) {
  cout << "in teacher-f(" << x << ")" << endl;
  return 46;
}

int main() {
  cout << "in teacher-main()" << endl;
  int x = 2;
  int y = g(x);
  cout << "g(" << x << ") returned " << y <<  endl;  
}

2nd file should contain the g method (+ forward declaration to f ):

teacher(teacher.cpp):

#include <iostream>
using namespace std;
int f(int x);

int g(int x) {
  cout << "in teacher-g(" << x << ")" << endl;
  int y = f(x);
  cout << "f(" << x << ") returned " << y << endl;  
  return 91;  
}

student (student.cpp):

#include <iostream>
using namespace std;
int f(int x);

int g(int x) {
  cout << "in student-g(" << x << ")" << endl;
  int y = f(x);
  cout << "f(" << x << ") returned " << y << endl;  
  return 82;  
}

now you can compile teacher from common.cpp + teacher.cpp

g++ -o teacher common.cpp teacher.cpp

and student from common.cpp + student.cpp

g++ -o student common.cpp student.cpp

The common.cpp can be even replaced by a static or shared library and you can add a header instead of the forward declaration of f .

This was from Lawrence and answers my question. I can't say about portability etc.

g++ -c student.cpp
g++ -c teacher.cpp 
strip -N main student.o
objcopy -W _Z1fi student.o
objcopy -W _Z1gi  teacher.o
g++ -o final teacher.o student.o
./final

giving the expected

in teacher-main()
in student-g(2)
in teacher-f(2)
f(2) returned 46
g(2) returned 82

Thanks!

PS I must have made a typo first time I tried it, or else the order of stripping and weakening is important... my comment to say this objcopy -W idea doesn't work has now been deleted. The above has been tested a few times now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM