Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

same template expansion in .lib conflicts with that in app using lib

jimdempseyatthecove
Honored Contributor III
395 Views

I am in the process of updating a template library I made several years ago. The purpose of the update was more as an experiment in using variadic templates. The prior template library was not variadic, the updated version is.

Note, I realize that I am still debugging the templates.

The templates are used in files inside a static library file (a handful of .objs).

Then I have a test program that runs through permutations of template arguments.

The library builds with warnings of duplicate functions (due to different sources expanding the same template).
These are warning (should be hushed up).

The test program compiles fine (no warnings, probably because I've #if 0'd all tests but the first two).

The problem comes in with the Link phase of linking the app against the library. In this case, the duplicate entries cause an error.

I thought (and my prior experience was) that template expanded code, when identical, was permitted to have a pass at duplicate functions.

1>------ Rebuild All started: Project: QuickThread, Configuration: Debug x64 ------
1>  Performing Custom Build Tools
...
1>parallel_pipeline.obj : :  warning LNK4006: "void __cdecl qt::qt_unwrap_fn_args(struct qt::unwrap_struct_t<void (__cdecl*)(void)> *)" (?qt_unwrap_fn_args@qt@@YAXPEAU?$unwrap_struct_t@P6AXXZ@1@@Z) already defined in QuickThread.obj; second definition ignored
1>parallel_manifold.obj : :  warning LNK4006: "void __cdecl qt::qt_unwrap_fn_args(struct qt::unwrap_struct_t<void (__cdecl*)(void)> *)" (?qt_unwrap_fn_args@qt@@YAXPEAU?$unwrap_struct_t@P6AXXZ@1@@Z) already defined in QuickThread.obj; second definition ignored
1>parallel_list.obj : :      warning LNK4006: "void __cdecl qt::qt_unwrap_fn_args(struct qt::unwrap_struct_t<void (__cdecl*)(void)> *)" (?qt_unwrap_fn_args@qt@@YAXPEAU?$unwrap_struct_t@P6AXXZ@1@@Z) already defined in QuickThread.obj; second definition ignored
1>parallel_allocator.obj : : warning LNK4006: "void __cdecl qt::qt_unwrap_fn_args(struct qt::unwrap_struct_t<void (__cdecl*)(void)> *)" (?qt_unwrap_fn_args@qt@@YAXPEAU?$unwrap_struct_t@P6AXXZ@1@@Z) already defined in QuickThread.obj; second definition ignored
1>  QuickThread.vcxproj -> C:\QuickThread\QuickThread_v4\x64\Debug\QuickThread.lib
2>------ Rebuild All started: Project: TemplateTestSuite, Configuration: Debug x64 ------
2>  stdafx.cpp
2>  TemplateTestSuite.cpp
...
2>QuickThread.lib(QuickThread.obj) : error LNK2005: "void __cdecl qt::qt_unwrap_fn_args(struct qt::unwrap_struct_t<void (__cdecl*)(void)> *)" (?qt_unwrap_fn_args@qt@@YAXPEAU?$unwrap_struct_t@P6AXXZ@1@@Z) already defined in TemplateTestSuite.obj
2>QuickThread.lib(parallel_allocator.obj) : error LNK2005: "void __cdecl qt::qt_unwrap_fn_args(struct qt::unwrap_struct_t<void (__cdecl*)(void)> *)" (?qt_unwrap_fn_args@qt@@YAXPEAU?$unwrap_struct_t@P6AXXZ@1@@Z) already defined in TemplateTestSuite.obj
...
2>C:\QuickThread\QuickThread_v4\x64\Debug\TemplateTestSuite.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========

Using VS 2013 with PS 2016 Update 2

Is there a linker option to have it check the duplicately named functions for same content, then ignore the second one?

Jim Dempsey

0 Kudos
3 Replies
jimdempseyatthecove
Honored Contributor III
395 Views

I found a poor work around. That is to force the function expansions to be inline. This seems somewhat wasteful on memory to me.

Jim Dempsey

0 Kudos
Melanie_B_Intel
Employee
395 Views

This might be useful: https://msdn.microsoft.com/en-us/library/by56e477.aspx

0 Kudos
jimdempseyatthecove
Honored Contributor III
395 Views

Nice article, but it does not fit my case.

The problem is some of the included .obj files within the library use a few instantiations of the templates. IOW require specific expansions.

By structuring the template in the code section of the files in the library as extern, this would indeed exclude those expansions from the library...

... however, this then requires the user code to expand the templates using <ArgT ...> unknown to it and hiding inside the library.

It would be klutzy to provide a .lib file plus a handful of .obj files, with which the user then figures out which ones to tack onto their build.

One also could use namespace to isolate the functions, but then you have an issue of code bloat, and/or versioning issues.

The best way would be for the linker to examine the .obj for duplicate named functions, and if identical, then either elide the extra instantiations or keep quiet (or with warning) continue with one chosen, and the others probably occupying memory. An implementation issue.

Back in the early days of C++ the linker would silently remove identical named member functions generated in different source files. I do not know what has changed now. In my case the affected codes are not member functions. i.e. they are program scoped functions.

Jim Dempsey

0 Kudos
Reply