简体   繁体   中英

Compile C code without it's main function

So I have several files for a University Project I'm working on; each file has several functions and a main function for testing purposes. However some of the files need to use functions from the others which gives linker complaints about multiple main declarations as to be expected. I was wondering if there was a way to compile these files to an object file without compiling the main function along the way, basically stripping out main to leave only the usable functions.

An example (not one of my actual files which are quite large), for each I'm assuming the existence of a header file which contains a declaration of foo and bar respectively:

//File foo.c
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"

int foo(int x, int y)
{
    return x + y;
}

//Assumes the user gives 2 integer inputs
int main(int argc, char **argv)
{
    int x, y;
    sscanf(argv[1], "%d", &x);
    sscanf(argv[2], "%d", &y);
    printf("foo(%d, %d) = %d\n", x, y, foo(x,y));
}

//File bar.c
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
#include "bar.h"

int bar(int x, int y, int z);
{
    return foo(x, y) * z;
}

//Assums the user gives 3 integer inputs
int main(int argc, char **argv)
{
    int x, y, z;
    sscanf(argv[1], "%d", &x);
    sscanf(argv[2], "%d", &y);
    sscanf(argv[3], "%d", &z);
    printf("bar(%d, %d, %d) = %d\n", x, y, z, bar(x, y, z));
}

Is it possible to compile foo.c to an object file so that I could call gcc bar.c foo.o and get an executable for bar.c ?

You can do an #ifdef on a symbol that you define only if you are compiling the file to generate the "test executable", and not when you use the file along with others; I've seen this being used for quick functional tests on small libraries.

#include "foo.h"

int foo(int x, int y)
{
    return x + y;
}

#ifdef COMPILE_MAIN
//Assumes the user gives 2 integer inputs
int main(int argc, char **argv)
{
    int x, y;
    sscanf(argv[1], "%d", &x);
    sscanf(argv[2], "%d", &y);
    printf("foo(%d, %d) = %d\n", x, y, foo(x,y));
}
#endif

Now you can do

gcc -DCOMPILE_MAIN foo.c -o foo.x

to make an executable foo.x that you can call directly to test foo , and you can do

gcc foo.c bar.c main.c -o yourapp.x

to make an executable using the other files (including the one with the "real" application main ) without complaints of multiply defined symbols.

If you're compiling your code using gcc or clang, you can declare the test main s as a weak symbol:

extern void main(int argc, char ** argv) __attribute__((weak));
void main(int argc, char ** argv) { ... }

The weak main will be used only in absence of a strong main .

For Visual Studio (from this answer ):

// in foo.cpp
extern "C" void main(int argc, char ** argv;
extern "C" void defaultMainFoo(int argc, char ** argv)
// different name for each file
{ ... }
#pragma comment(linker, "/alternatename:_main=_defaultMainFoo");

/alternatename means that the linker will use defaultMain for main if main is not elsewhere provided.

While putting #ifdef around your main functions works, IMO it's not the correct approach, especially since ...

[..] my actual files which are quite large [..]

The reasonable thing would be to separate your code into logical, reusable parts and to put each of these (small) parts into separate files.

A small example: Say you have a project foo which you're doing for your university, and part of it is to implement a linked list. The reasonable thing to do would be to create (at least) two source files, foo.c and list.c , and put the project specific parts (even if it's just some testing) into foo.c and all code regarding the implementation of your linked list into list.c . The interface of your linked list (ie probably some struct ... declaration, and functions to create and modify lists) is then put into a header file, list.h , which you include from any file needing linked list, such as a future project bar :

list.c

struct list * create_list(void) {
   // awesome code
}
// and more awesome code

list.h

struct list {
   // an awesome list
};
struct list * create_list(void); // <- only a declaration
// more awesome declarations

foo.c

#include "foo.h"
int main() {
  // awesome use of the list
  return 0;
}

bar.c

#include "foo.h"
int main() {
  // also awesome
  return 0;
}

Then you can either:

a) Compile each source file separately, and link the resulting object files together:

gcc -c list.c
gcc -c foo.c
gcc -o foo foo.o list.o

This is a way that's also perfectly expressible with make, in fact at least in GNU Make there's even an implicit rule to compile C files to object files ( %.o: %.c ).

Without link time optimization you may lose some optimizations with this approach. If your projects require different compiler flags, then this isn't a good approach.

b) Assemble a command line with the needed source files and do a single computation:

gcc -o foo foo.c list.c

You can do this with make, too, using for example a variable FOO_DEPENDENCIES := list.c .

Note that compile times will be far greater using this method.

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