2013-03-17 66 views
0

我遇到了爲包含3個C++文件的項目創建makefile的問題。不確定如何創建一個MakeFIle

雖然在包含文件(tree.h中,helperMethods.h和main.cpp中)的目錄,我首先使用命令的emacs makefile.make。然後,在emacs中,我寫爲生成文件:

all: tree.h helperMethods.h main.cpp 
[tab]g++ -std=c++0x -o project3 tree.h helperMethods.h main.cpp 

我已經手動驗證該命令克++ -std =的C++ 0x -o項目3 tree.h中helperMethods.h main.cpp中確實編譯這三個文件並創建一個可執行文件,它應該能夠工作。

之後,我保存makefile,退出emacs並嘗試運行它。

首先我以前使但這返回:

make: *** No targets specified and no makefile found. Stop. 

然後我試圖使用使-f makefile.make但這並沒有工作,要麼和返回:

make: Nothing to be done for `all'. 

在這一點上,我不確定爲什麼makefile沒有正確構建。我對makefile沒有太多的經驗;我很確定我的makefile正文中的命令是正確的,但是在我編寫它時沒有正確設置它。

如果是在所有相關的,這裏有3個文件:

tree.h中:

#ifndef tree_h 
#define tree_h 
#include <vector> 

using namespace std; 

template<class T> 
class tree 
{ 
public: 
    tree<T> * parent; 
    T element; 
    vector<tree<T> > nodes; 
    tree(const T& theElement) 
    { 
     element = theElement; 
     nodes = vector<tree<T> >(); 
    } 
    tree() 
    { 
     nodes = vector<tree<T> >(); 
    } 
}; 

#endif 

helperMethods.h

#ifndef helperMethods_h 
#define helperMethods_h 

#include "tree.h" 

#include <tuple> 
#include <string> 
#include <iostream> 
#include <vector> 

using namespace std; 

string printName(tuple<string, string, string> myTuple){ 
    string ret = ""; 
    if(std::get<0>(myTuple).length() > 0) 
     ret += get<0>(myTuple) + " "; 
    if(std::get<1>(myTuple).length() > 0 || std::get<2>(myTuple).length() > 0) 
     ret += "("; 
    if(std::get<1>(myTuple).length() > 0) 
     ret += get<1>(myTuple); 
    if(std::get<1>(myTuple).length() > 0 && std::get<2>(myTuple).length() > 0) 
     ret += ", "; 
    if(std::get<2>(myTuple).length() > 0) 
     ret += get<2>(myTuple); 
    if(std::get<1>(myTuple).length() > 0 || std::get<2>(myTuple).length() > 0) 
     ret += ")"; 
    return ret; 
} 

bool tupleContain(tuple<string, string, string> myTuple, string myString){ 
    return (std::get<0>(myTuple).compare(myString) == 0) || (std::get<1>(myTuple).compare(myString) == 0); 
} 

void findElement(tree<tuple<string, string, string> > myTree, string myString, bool* found, vector<int> *ret) 
{ 
    if(tupleContain(myTree.element, myString)) 
     *found = true; 
    if(! * found) 
    { 
     for(int counter = 0; counter < (int)myTree.nodes.size(); counter ++) 
     { 
      if(!* found) 
      { 
       (*ret).push_back(counter); 
       findElement(myTree.nodes.at(counter), myString, found, ret); 
       if(!* found) 
        (*ret).pop_back(); 
      } 
     } 
    } 
} 

void getLineage(tree<tuple<string, string, string> > myTree, string myString){ 
    bool dummyForFound = false; 
    bool * found = & dummyForFound; 
    vector<int> lineage = vector<int>(); 
    vector<int> * pointer = & lineage; 
    findElement(myTree, myString, found, &lineage); 
    if(lineage.size() == 0) 
    { 
     cout << "Species not present" << endl; 
     return; 
    } 
    vector<string> printString = vector<string>(lineage.size() + 1); 
    tree<tuple<string, string, string> > * currentNodePointer = & myTree; 
    for(int counter = 0; counter <= (int) lineage.size(); counter ++) 
    { 
     string currentLine = ""; 
     for(int counter2 = 0; counter2 < 2*((int) lineage.size() - counter); counter2 ++) 
      currentLine += ">"; 
     if(counter != lineage.size()) 
      currentLine += " "; 
     tree<tuple<string, string, string> > currentNode = * currentNodePointer; 
     currentLine += printName(currentNode.element); 
     if(counter < (int) lineage.size()) 
     { 
      int foo = lineage.at(counter); 
      tree<tuple<string, string, string> > currentNodeDummy = currentNode.nodes.at(foo); 
      *currentNodePointer = currentNodeDummy; 
     } 
     printString.at(counter) = currentLine; 
    } 
    for(int counter = 0; counter < (int) printString.size(); counter ++) 
     cout << printString.at(printString.size() - counter - 1) << endl; 
    cout << endl; 
} 

void getCommonLineage(tree<tuple<string, string, string> > myTree , string name1, string name2) 
{ 
    bool dummyForFound = false; 
    bool * found = & dummyForFound; 
    vector<int> lineage1 = vector<int>(); 
    vector<int> * pointer1 = & lineage1; 
    vector<int> lineage2 = vector<int>(); 
    vector<int> * pointer2 = & lineage2; 
    findElement(myTree, name1, found, pointer1); 
    * found = false; 
    findElement(myTree, name2, found, pointer2); 
    if(lineage2.size() == 0 || lineage1.size() == 0) 
    { 
     cout << "At least one species not present." << endl; 
     return; 
    } 
    bool stillSame = lineage1.at(0) == lineage2.at(0); 
    cout << "Level[0] Common Ancestor: ROOT (ROOT, ROOT)" << endl; 
    tree<tuple<string, string, string>> * lastSharedNode = & myTree; 
    int finalCounter = 0; 
    for(int counter = 0; counter < (int) min(lineage1.size(), lineage2.size()) && stillSame; counter ++) 
    { 
     tree<tuple<string, string, string> > dummyNode = * lastSharedNode; 
     tree<tuple<string, string, string> > currentNode = dummyNode.nodes.at(lineage1.at(counter)); 
     *lastSharedNode = currentNode; 
     if(counter < (int) min(lineage1.size(), lineage2.size()) - 1 && lineage1.at(counter + 1) != lineage2.at(counter + 1)) 
      stillSame = false; 
     tuple<string, string, string> currentElement = currentNode.element; 
     cout << "Level[" << counter + 1 << "] Commont Ancestor: " << printName(currentElement) << endl; 
     finalCounter ++; 
    } 
    cout << endl; 
    cout << "Ancestry unique to " << name1 << endl; 
    tree<tuple<string, string, string> > savedNode = *lastSharedNode; 
    tree<tuple<string, string, string> > * currentUnsharedNode = lastSharedNode; 
    for(int counter = finalCounter; counter < (int) lineage1.size(); counter ++) 
    { 
     tree<tuple<string, string, string> > dummyNode = * currentUnsharedNode; 
     tree<tuple<string, string, string> > currentNode = dummyNode.nodes.at(lineage1.at(counter)); 
     tuple<string, string, string> currentElement = currentNode.element; 
     *currentUnsharedNode = currentNode; 
     cout << "Level[" << counter + 1 << "] "; 
     if(counter == lineage1.size() - 1) 
      cout << "Species of interest: "; 
     cout << printName(currentElement) << endl; 
    } 
    cout << endl; 
    currentUnsharedNode = &savedNode; 
    cout << "Ancestry unique to " << name2 << endl; 
    for(int counter = finalCounter; counter < (int) lineage2.size(); counter ++) 
    { 
     tree<tuple<string, string, string> > dummyNode = * currentUnsharedNode; 
     tree<tuple<string, string, string> > currentNode = dummyNode.nodes.at(lineage2.at(counter)); 
     tuple<string, string, string> currentElement = currentNode.element; 
     *currentUnsharedNode = currentNode; 
     cout << "Level[" << counter + 1 << "] "; 
     if(counter == lineage2.size() - 1) 
      cout << "Species of interest: "; 
     cout << printName(currentElement) << endl; 
    } 
    cout << endl; 
} 
#endif 

的main.cpp

#include "rapidxml.h" 
#include "tree.h" 
#include "helperMethods.h" 

#include <string> 
#include <string.h> 
#include <stdio.h> 
#include <iostream> 
#include <vector> 
#include <queue> 
#include <tuple> 

using namespace rapidxml; 

int main(int argc, const char * arv[]){ 
    tuple<string, string, string> human ("Human", "Homo sapiens", "Species"); 
    tuple<string, string, string> apes ("Apes", "", ""); 
    tuple<string, string, string> dogs ("Dogs", "", ""); 
    tuple<string, string, string> root ("Root", "", ""); 
    tuple<string, string, string> bears ("Bears", "", ""); 
    tuple<string, string, string> cat ("Cat", "", ""); 
    tuple<string, string, string> horse ("Horse", "", ""); 
    tree<tuple<string, string, string> > myTree = tree<tuple<string, string, string>>(root); 
    tree<tuple<string, string, string> > b = tree<tuple<string, string, string>>(dogs); 
    tree<tuple<string, string, string> > c = tree<tuple<string, string, string>>(apes); 
    tree<tuple<string, string, string> > d = tree<tuple<string, string, string>>(bears); 
    tree<tuple<string, string, string> > e = tree<tuple<string, string, string>>(horse); 
    tree<tuple<string, string, string> > f = tree<tuple<string, string, string>>(human); 
    tree<tuple<string, string, string> > h = tree<tuple<string, string, string>>(cat); 
    d.nodes.push_back(f); 
    e.nodes.push_back(h); 
    b.nodes.push_back(d); 
    b.nodes.push_back(e); 
    myTree.nodes.push_back(b); 
    myTree.nodes.push_back(c); 
    cout << printName(myTree.nodes.at(0).element); 

    cout << "Welcome to my Tree of Life program!" << endl << endl; 

    int choice = 1; 
    while(choice == 1 || choice == 2) { 
     cout << "Please choose from the following options:" << endl; 
     cout << " 1.Get the lineage of a species" << endl; 
     cout << " 2.Get the commmon lineage of two species" << endl; 
     cout << " 3.Exit program" << endl << endl; 
     cin >> choice; 
     cout << endl; 
     if(choice == 1) 
     { 
      cout << "Please enter the name of the species of interest:" << endl; 
      string name; 
      cin >> name; 
      cout << endl; 
      getLineage(myTree, name); 
     } 
     if(choice == 2) 
     { 
      string name1, name2; 
      cout << "Please enter the name of the first species: " << endl; 
      cin >> name1; 
      cout << "Please enter the name of the second species: " << endl; 
      cin >> name2; 
      getCommonLineage(myTree, name1, name2); 
     } 
    } 
    return 0; 
} 
+2

提示:對於使用makefile的問題,發佈* entire * ** Makefile **可能會幫助您解決問題。如果上述事實上是你的整個Makefile,我建議你花一些時間在[GNU make online documentation]上(http://www.gnu.org/software/make/manual/)。 – WhozCraig 2013-03-17 06:24:34

+0

順便說一句,對於複雜的'Makefile'-s,你可以安裝然後使用'remake'而不是'make'(它們是兼容的),特別是用'-x'標誌來'remake' – 2013-03-17 07:51:57

+0

另一個關於style的注意事項:實踐是將定義放在.cpp文件中,並在頭文件中聲明(即只是函數原型,類定義等)。 – Wug 2013-03-18 02:45:15

回答

3

Makefile文件通常被稱爲Makefile(雖然makefile作品,太)不帶任何擴展。如果您使用的擴展名(不推薦),你必須告訴make生成文件的名稱。這是乏味和不必要的。

其次,你不需要把頭文件在編譯命令行,你不應該這樣做。在文件中使用#include行來指定頭文件。所以你的編譯命令可能是這樣的:

g++ -std=c++0x -o project3 main.cpp 

現在,在命令:

  • main.cpp

  • project3目標(即這將創建文件。)

另外:

  • tree.hhelperMethods.h所需的編譯工作;編譯取決於這個文件。 (你知道的,但他們沒有在命令行所以它不是明顯的顯示出來。)此外,如果改變了,你必須重新編譯您的文件。

一個Makefile介紹瞭如何從來源做出目標,並且還列出了依賴關係目標。 (從技術上講,使來源依賴之間沒有區別;它認爲兩者先決條件但它的方便識別的差異)

因此,對於上面的命令,整個化妝配方可能是這樣的:

project3: main.cpp tree.h helperMethods.h 
     g++ -std=c++0x -o project3 main.cpp 

通常情況下,我們不使用文件名像main.cpp;相反,我們會調用project3 project3.cpp的主文件,就像目標(輸出)文件是project3一樣。事實上,如果你這樣做,你沒有任何其他的依賴關係(頭文件),您可以鍵入:

make project3 

沒有makefile文件在所有make會拿出命令:

g++ -o project3 project3.cpp 

在這種情況下,因爲它沒有指定正確的C++標準的命令是錯誤的。但它經常起作用,並且使用相同的基本名稱命名目標和源代碼是一個很好的理由。

還有一件事:你的文件tree.h是一個只有標題的庫,這很好。但helperMethods.h只是假裝成一個頭文件。這是一個完整的實現。你應該解決這個問題。

另外,它的真的一個壞主意,把using namespace std在一個頭文件。頭文件應該明確地在需要它的所有東西上使用std::名稱空間前綴。一般不建議在任何地方使用using namespace std,但是它在頭文件中尤其糟糕,因爲它會默默地污染包含頭的任何文件的默認名稱空間。這可能會導致非常模糊的錯誤或編譯錯誤。

1

學校項目,呃? project3對於你自己的工作似乎是一個可怕的名字。

您不需要在生成文件處理中包含.h文件,因爲嚴格來說,它們永遠不需要獨立編譯。你的makefile需要一個規則,用於在main.cpp中構建main.o,然後創建一個用main.o構建可執行文件的規則。頭文件應該作爲main.o的依賴項添加,以便如果其中任何一個發生更改,make將知道從那裏重建。

基本上,它需要是這個樣子:

# http://stackoverflow.com/questions/15458126/unsure-how-to-create-a-makefile 
all: project3 

clean: 
    -rm main.o project3 

project3: main.o 
    g++ -std=c++0x -o project3 main.o 

main.o: main.cpp tree.h helperMethods.h 
    g++ -std=c++0x -c main.cpp 

別人可能會產生顯着不同,但同樣有效,生成文件用於這一目的。這個過程有一定的自由度。

這裏有一個規則來構建整個事物(請記住,如果沒有提供目標,則會自動選擇makefile中的第一個目標),清理所有中間文件的規則,構建規則來自目標文件的可執行文件以及從源文件構建目標文件的規則。這種方法不能很好地擴展;手工處理所有對更大,更復雜的makefile的依賴將是令人不愉快的,但在這種非常簡單的情況下就沒有問題。