大量 vcproj 构建顺序管理工具的实现(一)

1.引入问题

公司产品有大量模块(vcproj)需要在日常和出货时构建,有一个专门的批处理(BuildOrder_XXX.bat)去管理这些模块的构建顺序,每个开发者在写新模块后,都需要将它加入批处理文件内某一行,这没问题。但后续某个模块增加了对其它模块的隐式依赖(一般是使用了其它模块的导出函数)后,如果忘记也修改 vcproj 在批处理里的顺序,就会导致编译报错,需要跑几遍批处理,而且顺序也不太好调整。受困于此,我们可以引入构建顺序管理工具,专门用来分析和管理各模块的构建顺序。

2.分析问题

如何知道模块之间的隐式依赖关系呢?

首先想到的是 solution 文件内的项目依赖,但是如果开发者没有设置依赖关系怎么办?或者两个vcproj根本没有在同一个solution内怎么办?所以此办法无法解决问题。

接着想到的是 Dependency Walker,这个软件用来查看模块间的隐式依赖关系,是通过分析 PE 文件的导入表得来,需要先有编好的可执行文件,这个可以满足。网上查找到怎么获取PE导入表的代码如下:

HRESULT ParseFilePEDependency(LPCSTR szPEPath)
{
	HMODULE hMod = LoadLibraryExA(szPEPath, NULL, DONT_RESOLVE_DLL_REFERENCES);
	if( !hMod )
		return S_OK;	//输出文件不存在

	std::string sModDepend;
	do{
		// Import table
		IMAGE_DOS_HEADER* IDH = (IMAGE_DOS_HEADER*)hMod;
		if( !IDH )
			break;
		IMAGE_OPTIONAL_HEADER* IOH = (IMAGE_OPTIONAL_HEADER*)((BYTE*)hMod + IDH->e_lfanew + 24);
		if( !IOH )
			break;
		IMAGE_IMPORT_DESCRIPTOR* IID = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)hMod + IOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
		if( !IID )
			break;

		while(IID->FirstThunk)
		{
			IMAGE_THUNK_DATA* ITD =(IMAGE_THUNK_DATA*)((BYTE*)hMod+ IID->OriginalFirstThunk);
			if( IsBadReadPtr(ITD, sizeof(IMAGE_THUNK_DATA)) )
				break;

			sModDepend = ((char const *)hMod + IID->Name);//这个 sModDepend 就是每一个被 szPEPath 所隐式依赖的 DLL 名字了
			++IID;
		}
	}while(0);

	FreeLibrary(hMod);
	return S_OK;
}
实际跑起来后,发现另一个问题,sModDepend 会有许多 windows 自己的 DLL,例如 ntdll.dll, kernel32.dll 等,还有其它的我们不关心的无源码的第三方库,这些都可以排除。实际做法有两个:

第一个是从配置文件内读一个排除列表,这个方法比较麻烦,而且维护不易,因为外部DLL太多了,维护不易,废弃。

第二个是只记在批处理内的模块输出的可执行文件,这个方法比较好,但需要保证所有模块不能有相同的可执行模块名(相信每个大型软件都可以做到)。

想实现第二个办法,需要解析批处理文件、.sln文件和.vcproj文件。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值