所以我有一些我正在研究的大学项目的文件;每个文件都有几个函数和一个main
函数用于测试目的。但是,有些文件需要使用其他文件中的函数,这会给链接器提供关于预期的多个main
声明的投诉。我想知道是否有办法将这些文件编译到目标文件而不编译main
函数,基本上剥离main
只留下可用的函数。
一个例子(不是我的一个非常大的实际文件),我假设存在一个分别包含foo
和bar
声明的头文件:
//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
的可执行文件?
答案 0 :(得分:2)
只有在编译文件以生成&#34;测试可执行文件&#34;时才可以对您定义的符号执行#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.x
的可执行文件foo
,然后你可以
gcc foo.c bar.c main.c -o yourapp.x
使用其他文件(包括带有&#34;真实&#34;应用程序main
的文件)制作可执行文件,而不会抱怨多重定义的符号。
答案 1 :(得分:1)
如果您使用gcc或clang编译代码,则可以将测试main
声明为弱符号:
extern void main(int argc, char ** argv) __attribute__((weak));
void main(int argc, char ** argv) { ... }
只有在没有强main
的情况下才会使用弱main
。
对于Visual Studio(来自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
表示如果defaultMain
未在其他位置提供,则链接器将main
用于main
。
答案 2 :(得分:0)
虽然将#ifdef
main
功能放在你的foo
功能上,但IMO并不是正确的方法,尤其是因为......
[..]我的实际文件非常大[..]
合理的做法是将您的代码分成逻辑的,可重复使用的部分,并将每个(小)部分放入单独的文件中。
一个小例子:假设你有一个你为大学做的项目foo.c
,其中一部分是实施一个链表。合理的做法是创建(至少)两个源文件list.c
和foo.c
,并将项目特定部分(即使它只是一些测试)放入{{ 1}}以及关于将链接列表实现到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
)的隐含规则。 / p>
如果没有链接时间优化,您可能会失去一些使用此方法的优化。如果您的项目需要不同的编译器标志,那么这不是一个好方法。
b)使用所需的源文件组装命令行并执行单个计算:
gcc -o foo foo.c list.c
您也可以使用make来实现此功能,例如使用变量FOO_DEPENDENCIES := list.c
。
请注意,使用此方法编译时间会更长。