La extraña "advertencia LNK4042" de Visual Studio 2010

81

Una advertencia no trivial de Visual Studio 2010 (C ++) me ha golpeado en la cabeza (bastante difícilmente).

La compilación dio el siguiente resultado:

1 Debug \ is.obj: advertencia LNK4042: objeto especificado más de una vez; extras ignorados
1 Debug \ make.obj: advertencia LNK4042: objeto especificado más de una vez; extras ignorados
1 Debug \ view.obj: advertencia LNK4042: objeto especificado más de una vez; extras ignorados
1 identity.obj: error LNK2019: símbolo externo no resuelto void __cdecl test::identity::view(void)(? view @ identity @ test @@ YAXXZ) referenciado en la función void __cdecl test::identity::identity(void)(? identity @ 0test @@ YAXXZ)
1 identity.obj: error LNK2019: símbolo externo no resuelto void __cdecl test::identity::make(void)(? make @ identity @ test @@ YAXXZ) referenciado en la función void __cdecl test::identity::identity(void)(? identity @ 0test @@ YAXXZ)
1 range.obj: error LNK2019: símbolo externo no resuelto void __cdecl test::range::is(void)(? is @ range @ test @@ YAXXZ) referenciado en la función void __cdecl test::range::range(void)(? range @ 0test @@ YAXXZ)

Los errores del vinculador son siempre difíciles de depurar ... pero había referencias sin resolver, así que verifiqué ... pero la fuente está bien formada ... y finalmente me di cuenta:

Mi jerarquía de carpetas se ve así:

src/
  identity/
    is.cpp
    make.cpp
    view.cpp
  range/
    is.cpp
    make.cpp
    view.cpp

y también lo hace la jerarquía en la Solución (siempre la configuro para que imite la estructura de carpetas "real").

Y las salidas de diagnóstico:

Debug\is.obj
Debug\make.obj
Debug\view.obj

Junto con una advertencia que dice que .objse ha pasado dos veces al enlazador y que se ignorará.

No busque más: Visual ha aplanado perfectamente la jerarquía de mi carpeta y, por lo tanto, no puede compilar perfectamente el código fuente.

Por el momento, simplemente estoy pensando en cambiar el nombre de los archivos, eso debería cubrir el problema ...

... pero ¿hay alguna manera de que Visual Studio NO apile la jerarquía de archivos?

Matthieu M.
fuente
3
Acabo de conseguir lo mismo, realmente molesto que tengamos que "arreglarlo" manualmente. Me alegro de que hayas preguntado antes que yo. :)
GManNickG
5
Dejé la búsqueda de SO hace mucho tiempo. :) Google.
GManNickG
38
Acabo de resolver un problema similar en VS 2013. Para mí, el problema era que se estaba compilando un archivo de encabezado como si fuera un archivo C ++ independiente. Así que terminé con dos archivos de objeto con el mismo nombre: uno para foo.cpp y otro para foo.h. La solución fue ir a las páginas adecuadas para foo.h y cambiar Propiedades de configuración -> General -> Tipo de elemento a "Encabezado C / C ++" y hacer una compilación limpia.
Adrian McCarthy
1
@AdrianMcCarthy Tuve el mismo problema y tu sugerencia lo resolvió.
trenki
1
El comentario de @AdrianMcCarthy es la solución. Debe ser debido a que el asistente Agregar -> "Nuevo elemento" configura automáticamente el tipo de elemento del archivo.
Dustin Biser

Respuestas:

99

Solo quería publicar lo que creo que es la respuesta, si abre las propiedades para todo el proyecto y cambia el valor C/C++ -> Output Files -> "Object File Name"para que sea el siguiente:

$ (IntDir) /% (RelativeDir) /

Bajo VS 2010, creo que esto eliminará la ambigüedad de todos los archivos de objeto (ya que creo que Windows no le permitirá bajo ninguna circunstancia loca tener dos archivos con los mismos nombres en el mismo directorio). Consulte también los detalles aquí .

M. Tibbits
fuente
¡Ah! Eso es algo que tendré que probar tan pronto como regrese a casa: D
Matthieu M.
7
Solo para agregar: parece que% (RelativeDir) no elimina ningún ../ .. (no es que deba, pero tampoco parece haber ninguna alternativa) en su ruta, por lo que es posible que tenga que agregar un directorio "falso" para que sus archivos se creen en el directorio "correcto". Ejemplo, tengo $ (IntDir) / a / a /% (RelativeDir) / solo para que pueda construir en $ (IntDir) debido a dos ../ en la ruta de mi .cpp (las rutas son relativas a $ (ProjectDir ), Yo creo que). También tenga en cuenta que% (RelativeDir) está con% y $ (IntDir) está con $ (la respuesta es correcta, solo que leyendo rápido, ese hecho puede perderse).
n1ckp
2
Hm ... Me pregunto por qué esto no está configurado por defecto. Bueno, supongo que solo agregaré esto a cada proyecto (casi nada se compila sin esta solución)
Navin
Esto funcionó en la actualización 1 de Visual Studio 2012, pero desde que parcheé la actualización 4, VS parece que ya no quiere crear directorios intermedios para archivos de objetos. :( (Ver stackoverflow.com/questions/30212698. )
Thomas Young
¿Cómo hacer cuando lo uso cl.exeen CLI?
Aprendiendo
145

Tuve un problema similar con la advertencia del enlazador LNK4042: objeto especificado más de una vez; extras ignorados . En mi caso, Visual Studio estaba intentando compilar los archivos fuente y de encabezado con el mismo nombre, MyClass.hy MyClass.cpp. Sucedió porque cambié el nombre del .cpparchivo a .hy Visual Studio se confundió. Noté el problema al mirar los registros del compilador en el Debugdirectorio. Para resolverlo, simplemente elimine el .harchivo del proyecto y luego agréguelo nuevamente.

Andrey Levichev
fuente
2
¡Gracias por publicar esto! la vieja rutina de eliminar el archivo y agregarlo también funcionó para mí. Realmente estaba empezando a golpear mi cabeza contra la pared en este caso.
Wes
3
Gracias @AndreyLevichev: esta respuesta también solucionó el problema para mí. Está bastante claro en el archivo del proyecto que un archivo .h está en el grupo "ClCompile" en lugar del grupo "ClInclude"
jglouie
35
O puede hacer clic con el botón derecho en el foo.harchivo en el explorador de soluciones y establecer "Tipo de elemento" en "Encabezado C / C ++" en lugar de "Compilador C / C ++".
Thomas Eding
+1 para esto. Nunca hubiera encontrado mi problema si no hubiera visto tu comentario.
Crocboy
2
@Yaur - O mejor aún, cámbielo por una CLIncludeentrada
TED
8

Haga clic con el botón derecho en el archivo .cpp en la ventana del Explorador de soluciones, Propiedades, C / C ++, Archivos de salida, Configuración de nombre de archivo de objeto. El valor predeterminado es $(IntDir)\, eso es lo que hace el aplanamiento. Todo el archivo .obj irá a $ (IntDir), el directorio "Debug" en la configuración de depuración.

Puede cambiar la configuración, por ejemplo $(IntDir)\is2.obj. O seleccione todos los archivos de un grupo (use Shift + Click) y cambie la configuración a, digamos,$(IntDir)\identity\

O puede cambiar el nombre del archivo .cpp para que los archivos .obj no se sobrescriban entre sí. Tener archivos con exactamente el mismo nombre en dos directorios es un poco extraño.

O puede crear varios proyectos, creando, digamos, proyectos .lib para los archivos en identidad y rango. Se hace comúnmente en proyectos de archivos MAKE, por ejemplo. Sin embargo, eso hace que administrar la configuración de compilación y enlace sea más complicado a menos que utilice hojas de propiedades del proyecto.

Hans Passant
fuente
Gracias, ya he cambiado el nombre de los archivos porque era la forma más fácil de hacerlo. ¿No hay forma de pedirle a Visual que preserve la jerarquía que construí tan cuidadosamente en el Proyecto? Sé que tener el mismo nombre de archivo para varios archivos es extraño, pero prefiero agrupar cosas por subdirectorio en lugar de prefijar mis archivos ... ¡y es redundante ponerlos en un subdirectorio y prefijarlos con el nombre del subdirectorio!
Matthieu M.
Puede cambiar la configuración de varios archivos al mismo tiempo. Mantenga presionada la tecla CTRL mientras hace clic para seleccionarlos. Usar `$ (IntDir) \ $ (ParentName)` fue un problema la última vez que lo intenté.
Hans Passant
@Hans: supongo que seguiré usando nombres diferentes entonces, no estoy tan contento con la solución, pero como es solo para la parte de prueba unitaria, supongo que viviré con ella.
Matthieu M.
¿Es posible establecer $(IntDir)por archivo en una hoja de propiedades? Sé que puede configurarlo para todo el proyecto en una hoja de propiedades, pero no sé si puede configurarlo en función de la ruta del archivo que se está compilando. (Supongo que no, pero soy un novato de MSBuild completo)
James McNellis
@James, las hojas de propiedades del proyecto tienen un alcance de proyecto, afectan a todos los archivos.
Hans Passant
7

Haga clic derecho en el archivo de encabezado -> Propiedad -> ItemType (seleccione Encabezado C / C ++ ). Haga lo mismo con el archivo Cpp pero seleccione C / C ++ Compiler (es un trabajo para mí)

Phạm Mạnh
fuente
Esto era lo último que pensaría en buscar. Muchas gracias.
McLeary
4

Yo uso $ (IntDir) \% (Directory) \ en C / C ++ -> Archivos de salida -> "Nombre de archivo de objeto".

Csimbi
fuente
Si bien es esencialmente la misma que la respuesta aceptada, usar% (Directory) en lugar de% (RelativeDir) es un poco más seguro. Como señaló n1ckp en los comentarios de respuesta aceptados, dependiendo de cómo esté estructurado exactamente su proyecto en el disco, el directorio relativo puede terminar colocando sus archivos .obj en lugares inesperados.
user1593842
4

Alternativamente a eliminar y crear un nuevo archivo, puede cambiar la configuración de compilación / inclusión.

Vaya a su archivo project.vcxproj , ábralo con un editor, busque la línea html como<ItemGroup> .

Debería verse algo como:

<ItemGroup>
<ClCompile Include="implementation.cpp" />
</ItemGroup>

y

<ItemGroup>
<ClInclude Include="declaration.hpp" />
</ItemGroup>`

Suponiendo que sus archivos de implementación son .cpp y sus declaraciones son .hpp. Asegúrese de que todos sus archivos de implementación estén enumerados entre la primera sección si tiene más de uno e igualmente para la segunda sección para varios archivos de declaración.

user1222064
fuente
3

Tuve este problema con stdafx.cpp. De alguna manera stdafx.cpp se duplicó, por lo que hubo un segundo StdAfx.cpp (tenga en cuenta el caso diferente).

Después de eliminar StdAfx.cpp, ¡todo funcionó bien!

Usando VS 2010.

Knasterbax
fuente
Tuvo un problema similar, pero en lugar de duplicar el archivo, era el mismo archivo que aparece dos veces en ClCompile ItemGroup.
Nicholas Betsworth
2

Yo solía tener en el mismo proyecto .c y Cpp archivos con los mismos nombres de archivo . Los archivos estaban en carpetas por todas partes y las soluciones proporcionadas por otros crearon un desastre y un infierno de carpetas (en mi caso). ¡Incluso las versiones de lanzamiento sobrescriben las versiones de depuración !

Una buena solución (no perfecta) sería usar $ (ParentName), pero por alguna razón fuera del alcance de cualquiera, se ha eliminado de versiones posteriores de Visual Studio (2015+).

Lo que uso con éxito ahora es: $ (IntDir)% (Nombre de archivo)% (Extensión) .obj

que al menos separa los archivos de objeto .c construidos de .cpp .

Bill Kotsias
fuente