繁体   English   中英

编译C代码没有它的主要功能

[英]Compile C code without it's main function

所以我有一些我正在研究的大学项目的文件; 每个文件都有几个函数和一个用于测试目的的main函数。 但是,有些文件需要使用其他文件中的函数,这会给链接器提供关于预期的多个main声明的投诉。 我想知道是否有办法将这些文件编译到目标文件而不编译main功能,基本上剥离main只留下可用的功能。

一个例子(不是我的实际文件中的一个非常大),对于每个我假设存在一个包含foobar声明的头文件:

//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));
}

是否可以将foo.c编译为目标文件,以便我可以调用gcc bar.c foo.o并获取bar.c的可执行文件?

只有在编译文件以生成“测试可执行文件”时才可以对您定义的符号执行#ifdef ,而不是在将文件与其他文件一起使用时; 我已经看到这用于小型库的快速功能测试。

#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

现在你可以做到

gcc -DCOMPILE_MAIN foo.c -o foo.x

制作一个可以直接调用foo的可执行文件foo.x ,你可以这样做

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

使用其他文件(包括具有“真实”应用程序main文件的文件)生成可执行文件,而不会抱怨多重定义的符号。

如果您使用gcc或clang编译代码,则可以将测试main s声明为弱符号:

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

main将仅在没有强main情况下使用。

对于Visual Studio(来自此答案 ):

// 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表示如果main未在其他位置提供,则链接器将使用defaultMain作为main

虽然把#ifdef放在你的main功能上,但IMO并不是正确的做法,特别是因为...

[..]我的实际文件非常大[..]

合理的做法是将您的代码分成逻辑的,可重用的部分,并将这些(小)部分放入单独的文件中。

一个小例子:假设你有一个你正在为你的大学做的项目foo ,其中一部分是实现一个链表。 合理的做法是创建(至少)两个源文件foo.clist.c ,并将项目特定部分(即使只是一些测试)放入foo.c以及有关实现的所有代码你的链表到list.c 然后将链接列表的接口(即可能是一些struct ...声明,以及创建和修改列表的函数)放入头文件list.h ,该文件包含来自任何需要链表的文件,例如未来项目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;
}

然后你可以:

a)分别编译每个源文件,并将生成的目标文件链接在一起:

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

这种方式也可以用make完美表达,事实上至少在GNU中,甚至还有一个隐含的规则来将C文件编译为目标文件( %.o: %.c )。

如果没有链接时间优化,您可能会失去一些使用此方法的优化。 如果您的项目需要不同的编译器标志,那么这不是一个好方法。

b)使用所需的源文件组装命令行并执行单个计算:

gcc -o foo foo.c list.c

您也可以使用make来执行此操作,例如使用变量FOO_DEPENDENCIES := list.c

请注意,使用此方法编译时间会更长。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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