我正在开始一个C ++ OpenGL项目,我开始使用两个.cpp文件,Scene
和boilerplate
(没有.h文件!)。 boilerplate
包含简单设置环境的OpenGL过程。
我以为我会将它们移到这个单独的文件中,以便在Scene
中为自己留出更多空间,但现在我已经这样做并尝试在#include
中Scene
此文件,我在链接时遇到“重复符号”错误,例如
Scanning dependencies of target Coursework
[ 33%] Building CXX object CMakeFiles/Coursework.dir/Scene.cpp.o
[ 66%] Linking CXX executable Coursework
duplicate symbol __Z12checkGLErrorv in:
CMakeFiles/Coursework.dir/Scene.cpp.o
CMakeFiles/Coursework.dir/boilerplate.cpp.o
duplicate symbol __Z5setupv in:
CMakeFiles/Coursework.dir/Scene.cpp.o
CMakeFiles/Coursework.dir/boilerplate.cpp.o
duplicate symbol _height in:
CMakeFiles/Coursework.dir/Scene.cpp.o
CMakeFiles/Coursework.dir/boilerplate.cpp.o
...
每个“重复符号”都来自boilerplate.cpp
中的定义。
为什么我会收到这些错误?我认为#include
实际上与将文件的代码复制并粘贴到当前文件中是一样的,但是当我实际执行此操作时,它构建得很好。
我正在使用CMake构建,以防这是相关的(这是一个链接错误,所以它可能与此有关吗?)。
以下是供参考的文件,
Scene.cpp:
#include <iostream>
#include <glut/glut.h>
#include "boilerplate.cpp"
void draw() {
glClearColor(0.2f, 0.2f, 0.2f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// make beautiful models
glutSwapBuffers();
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
setup();
glutDisplayFunc(draw);
checkGLError();
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
boilerplate.cpp:
#include <glut/glut.h>
#include <cstdio>
int width, height;
void checkGLError() {
int e = 0;
GLenum error = glGetError();
while (GL_NO_ERROR != error) {
e++;
printf("GL Error %i: %s\n", e, gluErrorString(error));
error = glGetError();
}
}
void setup() {
width = 800;
height = 800;
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(width, height);
glutCreateWindow("Coursework");
}
void reshape(int _width, int _height) {
height = _height;
width = _width;
GLdouble aspect = static_cast<GLdouble>(width) / static_cast<GLdouble>(height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, aspect, 1, 1000);
glMatrixMode(GL_MODELVIEW);
}
的CMakeLists.txt:
cmake_minimum_required(VERSION 3.9)
project(Coursework)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
# Put directories in project's 'include path'
include_directories(${OPENGL_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS})
# Declare the var 'SOURCE_FILES', and give it all relevant source filenames
set(SOURCE_FILES Scene.cpp boilerplate.cpp)
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME} ${OPENGL_LIBRARIES} ${GLUT_LIBRARY})
答案 0 :(得分:2)
当你说#include
- 就像复制粘贴相应位置的内容时,你是对的。
但是如果你包含一个不仅包含声明和类定义的文件,还包含变量定义或函数/方法的实现,那么你可能会遇到麻烦......
a。)您要么在其他几个文件中包含相同的boilerplate.cpp
;这将导致重新定义相同的事物 - &gt;重复的符号错误
b。)您只在一个文件中包含boilerplate.cpp
,但编译器也将boilerplate.cpp
文件视为单独的翻译单元 - &gt;重复的符号
所以避免包括.cpp文件;而是将.cpp文件提供的函数作为函数原型(即没有正文的函数)暴露在适当的.h文件中;那么只包括.h文件。
答案 1 :(得分:0)
我的问题是我希望将#include
简单地用作复制粘贴工具,但我将CMake boilerplate.cpp
作为单独的可执行文件,并尝试将其链接< em>和 #include
它在Scene.cpp
中导致了这些重复的符号错误。
从CMake中删除boilerplate.cpp
,即从
set(SOURCE_FILES Scene.cpp boilerplate.cpp)
解决了这个问题并允许我构建它。
但正如评论所说,“正确的&#39;这样做的方法是给boilerplate.cpp
一个头文件并包含它。在我读到这篇文章之前,我无法理解为什么这是首选方式:
Why should I not include cpp files and instead use a header?