我正在学习SDL并完成了twinklebear tutorials。开始将代码分割成多个文件后,我的makefile停止工作,因此必须手动进行编译。它说:

make: *** No rule to make target `main.o', needed by `ooptest'.  Stop.

当我使用类似.cxx.o:的规则时,或者如果我为所有.cxx的规则分别制定规则:
g++ main.o -L/usr/local/lib -lSDL2 -Wl,-rpath=/usr/local/lib -o ooptest
main.o: In function `main':
main.cxx:(.text+0x247): undefined reference to `init(SDL_Window**, SDL_Renderer**)'
main.cxx:(.text+0x42e): undefined reference to `quit(SDL_Window**, SDL_Renderer**)'
collect2: error: ld returned 1 exit status
make: *** [ooptest] Error 1

我知道这是因为它仅链接main.o而不链接其他文件,但我不知道为什么。

这是7个相关的文件(除非可以帮助解决问题,否则请跳过这些文件,我不知道如何将它们放入扰流板之内):
生成文件:
CXX         = g++
SRCS        = main.cxx init.cxx quit.cxx
SDL_LIB     = -L/usr/local/lib -lSDL2 -Wl,-rpath=/usr/local/lib
SDL_INCLUDE = -I/usr/local/include
CXXFLAGS    = -Wall -c -std=c++11 $(SDL_INCLUDE)
LDFLAGS     = $(SDL_LIB)
OBJS        = $(SRCS:.cxx=.o)
EXE         = ooptest
all: $(EXE) $(SRCS)
$(EXE): $(OBJS)
    $(CXX) $< $(LDFLAGS) -o $@
main.o:
    $(CXX) $(CXXFLAGS) main.cxx -o $@
init.o:
    $(CXX) $(CXXFLAGS) init.cxx -o $@
quit.o:
    $(CXX) $(CXXFLAGS) quit.cxx -o $@
#.cxx.o:
#   $(CXX) $(CXXFLAGS) $< -o $@
clean:
    rm *.o && rm $(EXE)

main.h:
#ifndef _MAIN_
#define _MAIN_
#include <string>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
const int WIDTH=640;
const int HEIGHT=480;
void lgErr(std::string);
SDL_Texture*loadTex(const std::string&,SDL_Renderer*);
void renderTex(SDL_Texture*,SDL_Renderer*,int,int);
int main(void);
#endif

main.cxx:
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "main.h"
#include "init.h"
#include "quit.h"

using namespace std;

void lgErr(string msg){
    cout<<msg<<" error: "<<SDL_GetError()<<endl;
}

SDL_Texture* loadTex(const string &file,SDL_Renderer *ren){
    SDL_Texture *tex=0;
    SDL_Surface *img=SDL_LoadBMP(file.c_str());
    if(img){
        tex=SDL_CreateTextureFromSurface(ren,img);
        SDL_FreeSurface(img);
        if(tex==0)lgErr("CreateTextureFromSurface");
    }else
        lgErr("LoadBMP");
    return tex;
}

void renderTex(SDL_Texture *tex,SDL_Renderer *ren,int x,int y){
    SDL_Rect dst;
    dst.x=x;dst.y=y;
    SDL_QueryTexture(tex,NULL,NULL,&dst.w,&dst.h);
    SDL_RenderCopy(ren,tex,NULL,&dst);
}

int main(){
    SDL_Window *win;
    SDL_Renderer *ren;
    init(&win,&ren);
    SDL_Texture *bg=loadTex("bg.bmp",ren);
    SDL_Texture *fg=loadTex("fg.bmp",ren);
    if(bg==0 || fg==0)return 4;
    int bw,bh;
    SDL_QueryTexture(bg,NULL,NULL,&bw,&bh);
    SDL_RenderClear(ren);
    for(int i=0;i<WIDTH;i+=bw)
        for(int j=0;j<HEIGHT;j+=bh)
            renderTex(bg,ren,i,j);
    int fw,fh;
    SDL_QueryTexture(fg,NULL,NULL,&fw,&fh);
    int x=WIDTH/2-fw/2;
    int y=HEIGHT/2-fh/2;
    renderTex(fg,ren,x,y);
    SDL_RenderPresent(ren);
    SDL_Delay(2000);
    SDL_DestroyTexture(bg);
    SDL_DestroyTexture(fg);
    quit(&win,&ren);
}

init.h:
#ifndef _INIT_
#define _INIT_
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
int init(SDL_Window**,SDL_Renderer**);
#endif

init.cxx:
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "main.h"
#include "quit.h"

using namespace std;

int init(SDL_Window** win,SDL_Renderer** ren){
    if(SDL_Init(SDL_INIT_EVERYTHING)!=0){
        lgErr("SDL_Init");
        return 1;
    }
    *win=SDL_CreateWindow("Lesson 2",100,100,WIDTH,HEIGHT,SDL_WINDOW_SHOWN);
    if(*win==0){
        lgErr("CreateWindow");
        return 2;
    }
    *ren=SDL_CreateRenderer(*win,-1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if(*ren==0){
        lgErr("CreateRenderer");
        return 3;
    }
    return 0;
}

quit.h:
#ifndef _QUIT_
#define _QUIT_
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
void quit(SDL_Window**,SDL_Renderer**);
#endif

quit.cxx:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "main.h"
#include "init.h"

void quit(SDL_Window** win,SDL_Renderer** ren){
    SDL_DestroyRenderer(*ren);
    SDL_DestroyWindow(*win);
    SDL_Quit();
}

最后,我将GNU Make 3.81g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3和SDL2与图像库一起使用。

.cpp.o的makefile规则和$(EXE)的规则有什么问题?另外,我是否正确使用#include?

最佳答案

我认为问题出在这部分:

$(EXE): $(OBJS)
    $(CXX) $< $(LDFLAGS) -o $@

Make's documentation中:$<是第一个必备组件的名称,因此,它仅尝试与main.o链接。而是使用$^,它应该是所有先决条件。

10-07 15:55