0

I want to make a program which includes source files and header files from a sub-directory in addition to the main directory. The name of the sub-directory, and parts of the filenames themselves need to be chosen with a compiler constant. Here's an example file tree.

=main.h
=main.c
=anotherfile.h
=anotherfile.c
=A
---= A_file1.h
---= A_file1.c
---= A_file2.h
=B
---= B_file1.h
---= B_file1.c
---= B_file2.h

Every compilation involves main and anotherfile, which reference X_file1 and X_file2 where "X" is chosen at built time or with a constant. So the project can either be built with A files or B files.

So how does one (and what is the "best" way to) implement this? Can one put a reference to a compiler constant in an #include statement? (something like #include X+"/"+"x+"_file1.h) Or is there another way?

I'm very new to C build systems & the preprocessor so apologies if this is a poor question. Search engines have not been much help.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • If it's defined at built time you can consider compiling with `gcc ... -D path="/your/path"` and then `#include path"/XfileX.h"` in your units – David Ranieri Mar 21 '20 at 10:16
  • 2
    Actually I remember with Makefile you can choose which files you want to compile. Just have to set them in a Makefile rule and it does the job. https://www.gnu.org/software/make/manual/make.html – SidoShiro92 Mar 21 '20 at 10:32
  • With `gcc` command line you may indicates some include paths using the -I options, the path may be also relative paths.But better way is to use `make` with makefile. You may also use (in Linux, but I think also in Windows) environment variables. In bash you may use: `export MYINCLUDE=whatyounedd` and E.G. `gcc -I$MYINCLUDE.` also in make/makefile you may use the environ variables (see a make manual). – Sir Jo Black Mar 21 '20 at 11:24
  • This question is too broad - there is no "best" way. C is an old language and there are [a lot of build systems](https://en.wikipedia.org/wiki/List_of_build_automation_software). I advise to use [cmake](https://cmake.org/), there are many tutorials available online and it became really popular. The "some constant" should be configured by the user during `cmake` [configuration stage](https://cmake.org/runningcmake/) and then `cmake` can easily choose what library to compile. There is no need to name each file unique - I would name files in `A` and `B` the same. – KamilCuk Mar 21 '20 at 12:32
  • 2
    `something like #include X+"/"+"x+"_file1.h` - You can do something like that, but that would be (in my opinion) unreadable and unmaintainable - it will take new programmers real time to find what is going on. I would just have the build system setup proper include directory and have a constant `#include ` in your source. Finding files is the job for your compiler and tools around it, the source should have the logic. – KamilCuk Mar 21 '20 at 12:35
  • 1
    @DavidRanieri: string concatenation doesn't work in an `#include` statement, so that won't work. You can use [this technique](https://stackoverflow.com/questions/32066204/construct-path-for-include-directive-with-macro/32077478#32077478) but crafting a makefile is much cleaner. – rici Mar 21 '20 at 13:17
  • @rici oops, you're right. Thanks for the link – David Ranieri Mar 21 '20 at 22:11

1 Answers1

0

how does one implement this?

Either way, I would run to the build system. Configure the build system to compile the file multiple times with different macro definition that points to the file. A crude example:

// main.c
#include IMPL

And then for example with CMake build system:

add_executable(file1 main.c file1.c)
target_compile_definitoins(file1 PUBLIC "IMPL=\"file1.h\"")   
add_executable(file2 main.c file2.c)
target_compile_definitions(file1 PUBLIC "IMPL=\"file2.h\"")
# etc..

Overall, this approach seems wrong and confusing. Strongly consider rewriting your application, so that all files can be compiled together, and all symbols are unique - this will ease up writing and help with IDE to jump to proper function definition, and decrease your head pain.

If you are struggling with providing multiple implementations for the same interface, there is a solution - implement an interface object with function pointers. Then, choose the proper implementation with a constructor or a factory that constructs the object with the virtual interfaces.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111