Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

So here's the thing, and it's really just conceptual so don't let it bug you:

I've got reasons for not wanting to rely on a specific build system. I don't mean to dis anybody's favorite, but I really just want to stick to what comes with the compiler. In this case, GCC. Automake has certain compatibility issues, especially with Windows. <3 GNU make is so limited that it often needs to be supplemented with shell scripts. Shell scripts can take many forms, and to make a long story short and probably piss a lot of people off, here is what I want to do --

The main entry point is God. Be it a C or C++ source file, it is the center of the application. Not only do I want the main entry point to be the first thing that is executed, I also want it to be the first thing that is compiled. Let me explain --

There was a time when proprietary and closed-source libraries were common. Thanks to Apple switching to Unix and Microsoft shooting themselves in the foot, that time is over. Any library that needs to be dynamically linked can be included as a supporting file of the application. For that reason, separate build instructions for .SOs (and maybe .DLLs ;]) is all fine and dandy, because they are separate executable files. Any other library should be statically linked. Now, let's talk about static linking --

Static linking is a real bitch. That's what makefiles are for. If the whole project was written in one language (for instance C OR C++), you can #include the libraries as headers. That's just fine. But now, let's consider another scenario --

Let's say you're like me and can't be arsed to figure out C's difficult excuse for strings, so you decide to use C++. But you want to use a C library, like for instance MiniBasic. God help us. If the C library wasn't designed to conform to C++'s syntax, you're screwed. That's when makefiles come in, since you need to compile the C source file with a C compiler and the C++ source file with a C++ compiler. I don't want to use makefiles. Bear with me --

I would hope that there is a way to exploit GCC's preprocessor macros to tell it something like this:

````

Hi, GCC. How are you doing? In case you forgot, this source file you're looking at right now is written in C++. You should of course compile it with G++. There's another file that this file needs, but it's written in C. It's called "lolcats.c". I want you to compile that one with GCC into an object file and I want you to compile this one with G++ into the main object file, then I want you to link them together into an executable file.

````

How might I write such a thing in preprocessor lingo? Does GCC even do that?

share|improve this question
    
You could decide that all your things are plugins. –  Basile Starynkevitch Jul 20 at 11:29
3  
Your question is unclear. –  Basile Starynkevitch Jul 20 at 11:39

4 Answers 4

up vote 5 down vote accepted

The main entry point is God. Be it a C or C++ source file, it is the center of the application.

Only in the same way that nitrogen is the center of a pine tree. It is where everything starts, but there's nothing about C or C++ that makes you put the "center" of your application in main().

A great many C and C++ programs are built on an event loop or an I/O pump. These are the "centers" of such programs. You don't even have to put these loops in the same module as main().

Not only do I want the main entry point to be the first thing that is executed, I also want it to be the first thing that is compiled.

It is actually easiest to put main() last in a C or C++ source file.

C and C++ are not like some languages, where symbols can be used before they are declared. Putting main() first means you have to forward-declare everything else.

There was a time when proprietary and closed-source libraries were common. Thanks to Apple switching to Unix and Microsoft shooting themselves in the foot, that time is over.

"Tell 'im 'e's dreamin'!"

OS X and iOS are full of proprietary code, and Microsoft isn't going away any time soon.

What do Microsoft's current difficulties have to do with your question, anyway? You say you might want to make DLLs, and you mention Automake's inability to cope effectively with Windows. That tells me Microsoft remains relevant in your world, too.

Static linking is a real bitch.

Really? I've always found it easier than linking to dynamic libraries. It's an older, simpler technology, with fewer things to go wrong.

Static linking incorporates the external dependencies into the executable, so that the executable stands alone, self-contained. From the rest of your question, that should appeal to you.

you can #include the libraries as headers

No... You #include library headers, not libraries.

This isn't just pedantry. The terminology matters. It has meaning.

If you could #include libraries, #include </usr/lib/libfoo.a> would work.

In many programming languages, that is the way external module/library references work. That is, you reference the external code directly.

C and C++ are not among the languages that work that way.

If the C library wasn't designed to conform to C++'s syntax, you're screwed.

No, you just have to learn to use C++. Specifically here, extern "C".

How might I write such a thing in preprocessor lingo?

It is perfectly legal to #include another C or C++ file:

#include <some/library/main.cpp>

#include <some/other/library/main.c>
#include <some/other/library/secondary_module.c>

#include <iostream>

int main()
{
   call_the_library();
   do_other_stuff();
   return 0;
}

We don't use extern "C" here because this pulls the C and C++ code from those other libraries directly into our C++ file, so the C modules need to be legal C++ as well. There are a number of annoying little differences between C and C++, but if you're going to intermix the two languages, you're going to have to know how to cope with them regardless.

Another tricky part of doing this is that the order of the #includes is more sensitive than the order of library references if a linker command. When you bypass the linker in this way, you end up having to do some things manually that the linker would otherwise do for you automatically.

To prove the point, I took MiniBasic (your own example) and converted its script.c driver program to a standalone C++ program that says #include <basic.c> instead of #include <basic.h>. (patch) Just to prove that it's really a C++ program now, I changed all the printf() calls to cout stream insertions.

I had to make a few other changes, all of them well within a normal day's work for someone who's going to intermix C and C++:

  1. The MiniBasic code makes use of C's willingness to tolerate automatic conversions from void* to any other pointer type. C++ makes you be explicit.

  2. Newer compilers are no longer tolerating use of C string constants (e.g. "Hello, world!\n") in char* contexts. The standard says the compiler is allowed to place them into read-only memory, so you need to use const char*.

That's it. Just a few minutes work, patching GCC complaints.

I had to make some similar changes in basic.c to those in the linked script.c patch file. I haven't bothered posting the diffs, since they're just more of the same.

For another way to go about this, study the SQLite Amalgamation, as compared to the SQLite source tree. SQLite doesn't use #include all the other files into a single master file; they're actually concatenated together, but that is also all #include does in C or C++.

share|improve this answer

gcc will compile C and C and C++ as C++ simply as a result of you naming the files appropriately, the preprocessor doesn't come into that. You'll need extern "C" blocks around your C declarations in your C++ files to make sure the linker can link stuff correctly, though.

But what you're describing is almost never going to be helpful. If you're using a library that needs some kind of configuration to compile in the first place, then it's still going to need it if you just try to compile the files directly into your project. Not many real-world non-trivial libraries are pure ISO C that will compile on every platform without modification or some kind of configure script, so you'd be creating complexity most of the time, not reducing it, because you're going to have to deal with that configuration in your own build somehow.

share|improve this answer

No, you can't do that. There's no gcc pragma for compile in this way. The most similar is the Microsoft Visual C++ #pragma comment(lib, …) or #pragma comment(linker, …) [1] [2] for noting that some libraries should be included in the link procedure.

Hi, GCC. How are you doing? In case you forgot, this source file you're looking at right now is written in C++. You should of course compile it with G++. There's another file that this file needs, but it's written in C. It's called "lolcats.c". I want you to compile that one with GCC into an object file and I want you to compile this one with G++ into the main object file, then I want you to link them together into an executable file.

Your request is exactly what a Makefile does.

You could create a shell script that extracts the source files and compiles them with whatever command you want to use. But it's The Wrong Solution™

If you have multiple files, store them as multiple files. If you want people not to use make or cmake, don't provide a Makefile/CMakefile. Give them for instance a compile-me.sh file.

The only case when I feel I am in a similar situation is whan I code a util in a single file, but I simply provide the compilation command at the top inside a comment.

share|improve this answer

You could decide that all your things are plugins. Then compile them with gcc -shared -fPIC -O thing1.cc -o thing1.so and have a main stub program doing dlopen(3) on ./thing1.so then dlsym on God; on Linux you could have binfmt_misc tricks to make that more transparent.

If you insist on having self-containing programs, notice that GCC has the -ffreestanding option. It is then up to you to provide a runtime environment (at the very least, for some basic I/O thru system calls which you would need to interface, see syscalls(2)). Study carefully the relevant ABI spec. For Linux/x86-64 it is here. Read about calling conventions.

You could also customize GCC with compiler plugins like MELT (then you could add a #pragma which would do arbitrary things, perhaps even forking a gcc...)

BTW, an entry point like your God is not a source file, but some label known to the linker.

Reading more about compilers, linkers (see Levine's book: Linkers and Loaders, object files, ELF, libraries and shared objects (see Drepper's paper: How to Write Shared Libraries ...), crt0.o should help.

See also the C++ module draft proposal N3347

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.