VC,link error,ATL 链接错误"unresolved external symbol _main"

本文介绍了解决在Microsoft ATL 2.X环境下编译ATL工程时遇到的“unresolved externalsymbol_main”链接错误的方法。此错误通常发生在Release版本的编译过程中,而Debug版本则可以正常编译。文章分析了错误产生的原因在于预处理器定义了_ATL_MIN_CRT,导致CRT启动代码被移除。

标题  链接错误"unresolved external symbol _main"的解决     选择自 zhengyun_ustc 的 Blog
关键字  VC,link error,ATL
出处 

链接错误"unresolved external symbol _main"

Article last modified on 2002-3-2

------------------------------------------------------------

The information in this article applies to:

  - Microsoft ATL 2.X

------------------------------------------------------------

现象:

当你编译一个ATL工程的Release版时,你得到了下面这个链接错误:

   LIBCMT.LIB(crt0.obj) : error LNK2001: unresolved external symbol _main

如下图所示:

    Debug版本的编连却顺利通过。

 

原因与解决方法:

出错原因:

如果你在工程中使用了CRT函数,而这些函数又需要CRT启动代码,就会出现这种链接错误。默认情况下,Release配置的Preprocessor definitions中定义了_ATL_MIN_CRT,它将CRT启动代码从你的EXEDLL剔出去了。

 

 

背景知识:

1:

ATL支持把一个服务器编连优化成最小尺寸或者依赖性最小。我们可以定义三个预处理器符号来影响服务器的优化。

_ATL_MIN_CRT             服务器不链接标准的C/C++运行库

_ATL_DLL                  服务器动态链接工具函数库atl.dll

_ATL_STATIC_REGISTRY    服务器静态链接对组件注册的支持

如果定义了预处理器符号_ATL_MIN_CRT,那么我们的服务器不链接C/C++运行库,并且ATL提供了函数mallocreallocnewdelete的一个实现。当定义了这个符号时,我们不能调用任何其他的C/C++运行库的函数。否则,就会受到这样的待遇:

LIBCMT.LIB(crt0.obj) : error LNK2001: unresolved external symbol _main

ATL向导生成的ATL工程为所有的Release版本的编连定义了_ATL_MIN_CRT,但是没有为Debug版本定义这个符号。

Debug配置没有定义这三个符号中的任何一个。

RelMinSize配置定义了_ATL_MIN_CRT_ATL_DLL

RelMinDependency配置定义了_ATL_MIN_CRT_ATL_STATIC_REGISTRY

 

2:

C Run-Time Library (without iostream)

Characteristics

Option

Defined

LIBC.LIB

a statically linked library for single-threaded programs

(Single threaded, static link)

/ML

 

LIBCMT.LIB

a statically linked library that supports multithreaded programs

(Multithreaded, static link)

/MT

_MT

MSVCRT.LIB

Multithreaded, dynamic link (import library for MSVCRT.DLL)

/MD

_MT, _DLL

 

解决方法:

 

下面方法中的任何一个都可以纠正这个错误:

Ø         去除_ATL_MIN_CRT这个预处理符号;

Ø         打开stdafx.cpp,注释掉#include <atlimpl.cpp>这句话,然后编译,即可;

Ø         在工程的配置对话框的Link页面上,"ignore libraries"编辑框中输入Libcmt.lib,然后编译,如下图所示:

你将会得到几个“unresolved external”的错误,如下所示。

        这个列表就是你用到的CRT的函数。

Look for things that you think may be pulling in the startup code and remove them if you can.Instead, use their Win32 equivalents. For example, use lstrcmp() instead of strcmp(). Known functions that require CRT startup code are some of the string and floating point functions.

其他:

我的VC IDE6.0版本和SP5,如果用ATL COM AppWizard创建Service (EXE)工程。在这种情况下,它的RelMinDependency版本的配置中就没有定义_ATL_MIN_CRT符号!这和微软声称的“Service EXE Created with ATL COM AppWizard Doesn't Build in Release Mode”不一样,可能这是一个已经被FIX了的Bug

<think> 我们正在解决Tasking编译器报错`ltc E106: unresolved external: _main - (Ifx_Ssw_Infra.o)`的问题。根据错误信息,链接器(ltc)在链接阶段找不到`_main`函数的定义,该函数是C/C++程序的入口点。错误指向目标文件`Ifx_Ssw_Infra.o`,表明这个文件引用了`_main`,但链接器中找不到其实现。 ### 原因分析 1. **缺少主函数`main`**:C程序必须有一个`main`函数作为入口点。在单片机/嵌入式系统中,通常由启动代码(startup code)调用`main`函数。如果项目中没有定义`main`函数,或者定义不正确,就会导致此错误。 2. **启动文件配置错误**:嵌入式项目通常需要特定的启动文件(如`.s`或`.c`文件),该文件包含复位向量和初始化代码,最终会跳转到`main`函数。如果启动文件缺失或配置不正确,也会导致此问题。 3. **链接脚本配置错误**:链接脚本(.ld文件)可能未正确指定入口点(通常为`_start`或`main`)。 4. **编译器/链接器配置问题**:项目设置中可能未正确指定入口函数(例如,将入口函数设置为`main`,但实际函数名为`Main`或`app_main`等)。 ### 解决步骤 #### 1. **确认主函数存在** - 检查项目中是否包含`main`函数(注意:函数名必须为`main`,且符合C语言规范): ```c int main(void) { // 用户代码 while(1); return 0; } ``` - **注意**:嵌入式系统中通常使用`void`参数(无参数)且不返回(使用死循环)[^1]。 #### 2. **检查启动文件** - 启动文件(如`Ifx_Ssw_Infra.c`或`startup_*.s`)负责初始化硬件并调用`main`。确保: - 启动文件已加入项目(在Tasking IDE中,通常位于`Libraries/Startup`目录)。 - 启动文件中包含对`main`的调用(示例为汇编代码): ```assembly ; 复位处理函数 Reset_Handler: BL _main ; 跳转到main函数 ``` - 如果启动文件调用的是`_main`(带下划线),而你的主函数名为`main`(无下划线),可能需要使用编译选项`--underscore`(或类似选项)确保符号匹配。 #### 3. **配置链接器入口点** - 在Tasking链接器设置中指定入口点(Entry Point): 1. 右键项目 → Properties → **TASKING Linker** → **Output** 2. 设置`Entry symbol`为`_start`(通常由启动文件提供)或直接设置为`main`(如果启动文件已正确链接): ```plaintext Entry symbol: _start ; 或 main ``` ![](https://static.tasking.com/docs/linker_entry.png) [^2] #### 4. **检查链接脚本(.ld文件)** - 确认链接脚本中指定了正确的入口点(通常在`.ld`文件开头): ```ld ENTRY(_start) ; 或 ENTRY(main) ``` - 如果没有自定义链接脚本,则使用默认配置(通常不需要修改);若修改过,需确保与启动文件匹配。 #### 5. **验证编译器/链接器选项** - **禁用最小化CRT库**:类似VC++的`_ATL_MIN_CRT`[^4],Tasking可能因优化设置跳过了标准启动代码: - 在编译器设置中,确保未定义类似`TASKING_MIN_CRT`的宏。 - **添加标准库链接**:确认链接了包含`_main`实现的库(如`libc.a`): - 在Linker → Libraries中添加`c`(表示链接libc.a): ```plaintext Libraries: c ; 其他库按需添加 ``` #### 6. **处理函数名修饰问题(C++项目)** - 如果项目是C++,`main`函数需用`extern "C"`修饰,避免名称修饰(name mangling): ```cpp extern "C" { int main(void) { /* ... */ } } ``` ### 验证步骤 1. 清理项目(Project → Clean)。 2. 重新编译并查看链接错误是否消失。 > ⚠️ **若仍报错**:查看生成的映射文件(.map): > 1. 在Linker → Output中勾选`Generate map file`。 > 2. 编译后打开.map文件,搜索`_main`,确认其是否存在(地址非0)。 > 3. 检查启动文件中的调用点(如`BL _main`)是否与.map中的符号一致。 §§相关问题§§ 1. Tasking编译器中如何配置自定义启动文件? 2. 如何解决Tasking链接错误"undefined symbol _exit"? 3. Tasking项目中如何修改堆栈大小? --- [^1]: C语言标准要求程序入口点为`main`函数 [^2]: TASKING Linker手册, "指定入口点"章节 [^4]: MSDN文档, LNK2001错误解决方案 </think> ### 解决Tasking编译错误`ltc E106: unresolved external: _main`的方法 该错误表明链接器找不到程序入口点`main`函数,常见于嵌入式开发项目中缺少主函数或入口配置错误。以下是系统性的解决步骤: --- #### 1. **确认主函数存在** - 检查项目中是否包含`main`函数(函数名必须为`main`): ```c int main(void) { // 初始化代码 while(1); // 主循环 return 0; } ``` - **位置要求**:单片机项目中`main`通常位于启动文件(如`Ifx_Ssw_Infra.c`)或应用层主文件。 #### 2. **检查启动文件配置** - 确认启动文件包含对`main`的调用(示例为伪代码): ```c void Reset_Handler(void) { SystemInit(); // 系统初始化 __main(); // C库初始化(关键!) main(); // 跳转到用户main函数 } ``` - 若使用自定义启动文件,确保链接了正确的启动代码(如`cstart.o`)[^4]。 #### 3. **验证链接器配置** - **在Tasking IDE中**: 1. 右键项目 → Properties → **TASKING Linker** → **Output** 2. 确认`Entry symbol`设置为`Reset_Handler`(或其他启动函数) ![](https://static.tasking.com/docs/linker_entry.png) - **在链接脚本(.ld文件)中**: ```ld ENTRY(Reset_Handler) /* 指定入口点 */ ``` #### 4. **检查标准库链接** - 确保链接了C标准库(包含`__main`初始化代码): ```plaintext [Linker配置] Libraries: c # 添加libc.a ``` - **注意**:某些优化配置(如`_ATL_MIN_CRT`)会移除启动代码[^4],需禁用此宏。 #### 5. **处理函数名修饰问题** - 如果是C++项目,使用`extern "C"`确保符号名不被修饰: ```cpp extern "C" { int main(void); // 强制使用C链接规则 } ``` #### 6. **验证堆栈初始化代码** - 在启动文件中显式初始化堆栈指针(针对某些单片机架构): ```assembly LDR SP, =_estack /* 设置堆栈指针 */ BL __main /* 调用C库初始化 */ ``` --- ### 验证步骤 1. 清理项目:`Project → Clean All` 2. 重新编译并观察映射文件(.map): ```plaintext Symbol Table: _main 0x80000000 Code << 确认地址非0 Reset_Handler 0x80000100 Code ``` > ⚠️ **高级排查**: > 使用`--map-file`生成详细映射表,检查`_main`是否被优化: > ```plaintext > ltc --map-file -o output.elf ... > ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值