Mac CMake C++SDL2用于体系结构x86_64的重复符号



我正在youtube上学习2017年完成的关于C++和SDL2的教程,由于这个错误,我无法继续学习。我刚开始在Mac上工作,并认为错误是由于CMake或使用VS代码造成的,所以我安装了Qt创建者,但我仍然收到同样的错误。我研究过这个错误,但我不明白问题出在哪里,希望有人能帮助我理解。我的假设是,这与Game.cpp中新的GameObject和新地图的行有关。

感谢您的帮助。

错误:

18:19:19: Running steps for project cpp...
18:19:19: Starting: "/Users/m/Qt/Tools/CMake/CMake.app/Contents/bin/cmake" --build . --target all
[1/6 2.1/sec] Building CXX object CMakeFiles/cpp.dir/GameObject.cpp.o
[2/6 4.2/sec] Building CXX object CMakeFiles/cpp.dir/TextureManager.cpp.o
[3/6 6.2/sec] Building CXX object CMakeFiles/cpp.dir/main.cpp.o
[4/6 8.3/sec] Building CXX object CMakeFiles/cpp.dir/Map.cpp.o
[5/6 10.2/sec] Building CXX object CMakeFiles/cpp.dir/Game.cpp.o
[6/6 8.8/sec] Linking CXX executable cpp
FAILED: cpp 
: && /usr/bin/clang++  -g -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names  CMakeFiles/cpp.dir/main.cpp.o CMakeFiles/cpp.dir/Game.cpp.o CMakeFiles/cpp.dir/GameObject.cpp.o CMakeFiles/cpp.dir/Map.cpp.o CMakeFiles/cpp.dir/TextureManager.cpp.o  -o cpp -F/Library/Frameworks -Wl,-rpath,/Library/Frameworks  -framework  SDL2  -framework Cocoa  -framework  SDL2_image && :
duplicate symbol 'TextureManager::Draw(SDL_Texture*, SDL_Rect, SDL_Rect)' in:
CMakeFiles/cpp.dir/Game.cpp.o
CMakeFiles/cpp.dir/GameObject.cpp.o
duplicate symbol 'TextureManager::Draw(SDL_Texture*, SDL_Rect, SDL_Rect)' in:
CMakeFiles/cpp.dir/Game.cpp.o
CMakeFiles/cpp.dir/Map.cpp.o
duplicate symbol 'TextureManager::Draw(SDL_Texture*, SDL_Rect, SDL_Rect)' in:
CMakeFiles/cpp.dir/Game.cpp.o
CMakeFiles/cpp.dir/TextureManager.cpp.o
ld: 3 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
18:19:20: The process "/Users/m/Qt/Tools/CMake/CMake.app/Contents/bin/cmake" exited with code 1.
Error while building/deploying project cpp (kit: Desktop Qt 5.15.1 clang 64bit)
When executing step "CMake Build"
18:19:20: Elapsed time: 00:01.

TextureManager.cpp:

#include "TextureManager.h"
SDL_Texture* TextureManager::LoadTexture(const char* texture)
{
SDL_Surface* tempSurface = IMG_Load(texture);
SDL_Texture* tex = SDL_CreateTextureFromSurface(Game::renderer, tempSurface);
SDL_FreeSurface(tempSurface);
return tex;
}

TextureManager.h:

#include "Game.h"
class TextureManager {
public:
static SDL_Texture* LoadTexture(const char* fileName);
static void Draw(SDL_Texture* tex, SDL_Rect src, SDL_Rect dest);
};
void TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}

Game.cpp:

#include "Game.h"
#include "TextureManager.h"
#include "GameObject.h"
#include "Map.h"
GameObject* player;
GameObject* enemy;
Map* map;
SDL_Renderer* Game::renderer = nullptr;
Game::Game()
{}
Game::~Game()
{}
void Game::init(const char *title, int xpos, int ypos, int width, int height, bool fullscreen)
{
int flags = 0;
if(fullscreen)
{
flags = SDL_WINDOW_FULLSCREEN;
}
if(SDL_Init(SDL_INIT_EVERYTHING) == 0)
{
std::cout << "Subsystems Initialized..." << std::endl;
window = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
if(window)
{
std::cout << "Window created..." << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, 0);
if(renderer)
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
std::cout << "Renderer created..." << std::endl;
}
isRunning = true;
} else {
isRunning = false;
}
player = new GameObject("../assets/player.png", 0, 0);
enemy = new GameObject("../assets/enemy.png", 50, 50);
map = new Map();
}
void Game::handleEvents()
{
SDL_Event event;
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
isRunning = false;
break;
default:
break;
}
}
void Game::update()
{
player->Update();
enemy->Update();
}
void Game::render()
{
SDL_RenderClear(renderer);
map->DrawMap();
player->Render();
enemy->Render();
SDL_RenderPresent(renderer);
}
void Game::clean()
{
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
std::cout << "Game cleaned..." << std::endl;
}

游戏.h:

#ifndef Game_hpp
#define Game_hpp
#include <SDL2/SDL.h>
#include "SDL_image.h"
#include <iostream>
class Game {
public:
Game();
~Game();
void init(const char* title, int x, int y, int width, int height, bool fullscreen);
void handleEvents();
void update();
void render();
void clean();
bool running() { return isRunning; }
static SDL_Renderer *renderer;
private:
int cnt = 0;
bool isRunning;
SDL_Window *window;
};
#endif /* Game_hpp */

GameObject.cpp:

#include "GameObject.h"
#include "TextureManager.h"
GameObject::GameObject(const char* texturesheet, int x, int y)
{
objTexture = TextureManager::LoadTexture(texturesheet);
xpos = x;
ypos = y;
}
void GameObject::Update()
{
xpos++;
ypos++;
srcRect.h = 32;
srcRect.w = 32;
srcRect.x = 0;
srcRect.y = 0;
destRect.x = xpos;
destRect.y = ypos;
destRect.h = srcRect.h * 2;
destRect.w = srcRect.w * 2;
}
void GameObject::Render()
{
SDL_RenderCopy(Game::renderer, objTexture, &srcRect, &destRect);
}

GameObject.h:

#pragma once
#include "Game.h"
class GameObject {
public:
GameObject(const char* texturesheet, int x, int y);
~GameObject();
void Update();
void Render();
private:
int xpos;
int ypos;
SDL_Texture* objTexture;
SDL_Rect srcRect, destRect;

};

Map.cpp:

#include "Map.h"
#include "TextureManager.h"
int lvl1[20][25] = {
{ 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
};
Map::Map()
{
dirt = TextureManager::LoadTexture("../assets/dirt.png");
grass = TextureManager::LoadTexture("../assets/grass.png");
water = TextureManager::LoadTexture("../assets/water.png");
LoadMap(lvl1);
src.x = src.y = 0;
src.w = dest.w = 32;
src.h = dest.h = 32;
dest.x = dest.y = 0;
}
void Map::LoadMap(int arr[20][25])
{
for (int row = 0; row < 20; row++)
{
for (int column = 0; column < 25; column++)
{
map[row][column] = arr[row][column];
}
}
}
void Map::DrawMap()
{
int type = 0;
for (int row = 0; row < 20; row++)
{
for (int column = 0; column < 25; column++)
{
type = map[row][column];
dest.x = column * 32;
dest.y = row * 32;
switch (type)
{
case 0:
TextureManager::Draw(water, src, dest);
break;
case 1:
TextureManager::Draw(grass, src, dest);
break;
case 2:
TextureManager::Draw(dirt, src, dest);
break;
default:
break;
}
}
}
}

Map.h:

#pragma once
#include "Game.h"
class Map
{
public:
Map();
~Map();
void LoadMap(int arr[20][25]);
void DrawMap();
private:
SDL_Rect src, dest;
SDL_Texture* dirt;
SDL_Texture* grass;
SDL_Texture* water;
int map[20][25];
};

main.cpp:

#include "Game.h"
Game *game = nullptr;
int main(int argc, const char * argv[]) {
const int FPS = 60;
const int frameDelay = 1000 / FPS;
Uint32 frameStart;
int frameTime;
game = new Game();
game->init("2D Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 640, false);
while (game->running())
{
frameStart = SDL_GetTicks();
game->handleEvents();
game->update();
game->render();
frameTime = SDL_GetTicks() - frameStart;
if(frameDelay > frameTime)
{
SDL_Delay(frameDelay - frameTime);
}
}
game->clean();
return 0;
}

此问题已通过drescherjm的注释解决。

通过在TextureManager.h:中添加inline

#include "Game.h"
class TextureManager {
public:
static SDL_Texture* LoadTexture(const char* fileName);
static void Draw(SDL_Texture* tex, SDL_Rect src, SDL_Rect dest);
};
void inline TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}

或者在TextureManager.h中删除该函数并将其添加到TextureManager.cpp:中

#include "TextureManager.h"
SDL_Texture* TextureManager::LoadTexture(const char* texture)
{
SDL_Surface* tempSurface = IMG_Load(texture);
SDL_Texture* tex = SDL_CreateTextureFromSurface(Game::renderer, tempSurface);
SDL_FreeSurface(tempSurface);
return tex;
}
void TextureManager::Draw(SDL_Texture * tex, SDL_Rect src, SDL_Rect dest)
{
SDL_RenderCopy(Game::renderer, tex, &src, &dest);
}

最新更新