How to share one main function/file amongst many projects?


How to share one main function/file amongst many projects?



I have multiple C++ applications that have the same main file.
It looks something like this:


main() {
superclass *a = new subclass_1();
a.setup(); // .setup() and .run() are superclass functions that are overridden by subclasses.
a.run();
}



I have about 10 subclasses (subclass_1, subclass_2, subclass_3, etc...) that all share the same interface (.setup(), .run()).



I'd like to create 10 separate binaries with the exact same main file but with the slight difference that the subclass instance is different (instead of new subclass_1(), it'll be new subclass_2(), new subclass_3(), etc..). But the calls to .setup() and .run() will always be the same.



The reasoning behind this is that my main function might change slightly, and I wouldn't want to update 10 main files to propagate this change. I'd like to just have one main file and somehow link to 10 different subclass libraries to create 10 different executables.



I'm using CMake and C++ 17, with gcc/g++ of course.



Strategies I've considered:



a) Use a templating engine that takes a main file template and generates 10 temporary main failes and compiles them. This is not very elegant but I can probably hack CMake to do the process for me.



b) Use C's dynamic class loading. Using dlopen and dlsym, I can export the symbols from my subclasses and have a general main file .o file that I can link individually to each subclass lib and create 10 different binaries that simply loads 10 different .so files for each subclass. This method is a bit more elegant but could be ugly and messy, and unfortunately I'm using C++ with args inside my setup and run functions that are std::strings. The symbol exporting could get messy....



Anyone encountered something like this? Any ideas?





This doesn't sound like "many projects". It sounds like "one project, many binaries", which takes no effort at all.
– o11c
Jul 2 at 3:20





Sure, if we go with that, how would you go about it?
– Robert
Jul 2 at 3:24





One simple way is CLASS a; a.setup(); a.run(); where CLASS is a macro provided on the compiler command line. Compile 10 executables each with a different subclass provided as CLASS
– user4581301
Jul 2 at 3:26



CLASS a; a.setup(); a.run();


CLASS


CLASS





If you could let go C++ (or at least created wrapper functions in C), you wouldn't have a problem: the main execute would call dlopen+dlsym; its parameter would be the name of the actual shared object.
– Lorinczy Zsigmond
Jul 3 at 9:30




2 Answers
2



You could use a compiler defined MACRO like this:


MACRO


// main.cpp

int main() {
// macro defined by compiler command line
superclass *a = new DEFINED_SUBCLASS();
a.setup(); // .setup() and .run() are superclass functions that are overridden by subclasses.
a.run();
}



Compile with:


g++ -DDEFINED_SUBCLASS=subclass_1 -std=c++11 -o main-1 main.cpp
g++ -DDEFINED_SUBCLASS=subclass_2 -std=c++11 -o main-2 main.cpp
... etc ...



You don't have to hack your CMake. Add the following to your CMakeLists.txt:


foreach(subclass IN ITEMS 1 2 3)
configure_file("main.cpp.in"
"${CMAKE_CURRENT_BINARY_DIR}/main-${subclass}.cpp" @ONLY
)
add_executable(foo-${subclass} main-${subclass}.cpp)
target_include_directories(foo-${subclass}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
)
endforeach()



Update the loop as needed with your correct items. The main.cpp.in should look something like this:


#include "classes.h"

int main() {
superclass * a = new subclass@subclass@{};
a->setup();
a->run();
return 0;
}



Adjust as necessary (this is a bare-bones example to match yours). This will give you a target for each generated file:


$ make
[ 16%] Building CXX object CMakeFiles/foo-1.dir/main-1.cpp.o
[ 33%] Linking CXX executable foo-1
[ 33%] Built target foo-1
[ 50%] Building CXX object CMakeFiles/foo-3.dir/main-3.cpp.o
[ 66%] Linking CXX executable foo-3
[ 66%] Built target foo-3
[ 83%] Building CXX object CMakeFiles/foo-2.dir/main-2.cpp.o
[100%] Linking CXX executable foo-2
[100%] Built target foo-2



And for completeness, classes.h:


struct superclass {
virtual void setup() = 0;
virtual void run() = 0;
};

struct subclass1 : superclass {
void setup() override { }
void run() override { }
};

struct subclass2 : superclass {
void setup() override { }
void run() override { }
};

struct subclass3 : superclass {
void setup() override { }
void run() override { }
};





This could be great. Except I have to really merge all these subclasses and CMake files into one directory / project. This might be tough as I might have 100 different subclasses with different people working on them. This could get unruly really fast. I'd prefer to somehow make a "library that includes a main file" and people can make a subclass anywhere and link to this library to generate an executable.
– Robert
Jul 2 at 3:39





Best option then is wrap the main generation in a CMake function/macro and build static libraries instead of executables. You'd have to make it a bit more generic so you can add the appropriate include paths, but that way you don't have to reorganize the project.
– Stephen Newell
Jul 2 at 3:47






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages