0

3 つの C++ ファイルを含むプロジェクトのメイクファイルの作成に問題があります。

ファイル (tree.h、helperMethods.h、および main.cpp) を含むディレクトリで、最初にコマンドemacs makefile.makeを使用します。次に、emacs で、makefile を次のように記述します。

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

コマンドg++ -std=c++0x -o project3 tree.h helperMethods.h main.cppが実際に 3 つのファイルをコンパイルし、そこで動作する実行可能ファイルを作成することを手動で確認しました。

この後、makefile を保存し、emacs を終了して、実行を試みます。

最初にmakeを使用しましたが、これは返されました:

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

次に、make -f makefile.makeを使用してみましたが、これも機能せず、次のように返されました。

make: Nothing to be done for `all'.

この時点で、makefile が適切に作成されなかった理由がわかりません。私はメイクファイルの経験があまりありません。メイクファイルの本体にあるコマンドは正しいと確信していますが、作成時に適切に設定していませんでした。

関係がある場合は、次の 3 つのファイルを参照してください。

ツリー.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;
}
4

2 に答える 2

3

Makefileは通常、拡張子なしで呼び出されMakefileます(ただし、機能します)。makefile拡張機能(非推奨)を使用する場合makeは、makefileの名前を指定する必要があります。それは退屈で不必要です。

次に、コンパイルコマンドラインにヘッダーファイルを配置する必要はありません。また、そうするべきではありません。ファイル内の行を使用#includeして、ヘッダーファイルを指定します。したがって、コンパイルコマンドは次のようになります。

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

さて、そのコマンドで:

  • main.cppソースです

  • project3ターゲット(つまり、作成されるファイル)です。

また:

  • tree.hhelperMethods.hコンパイルが機能するために必要です。コンパイルはこのファイルに依存します。(ご存知のとおりですが、コマンドラインに表示されないため、わかりません。)さらに、変更された場合は、ファイルを再コンパイルする必要があります。

makefileは、そのソースからターゲットを作成する方法を説明し、ターゲット依存関係もリストします。(技術的には、makeはソース依存関係を区別しません。両方を前提条件と見なします。ただし、違いを認識すると便利です。)

したがって、上記のコマンドの場合、makeレシピ全体は次のようになります。

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

main.cpp通常、 ;のようなファイル名は使用しません。project3.cppむしろ、ターゲット(出力)ファイルがであるのと同じように、project3のメインファイルを呼び出しますproject3。実際、それを実行し、他の依存関係(ヘッダーファイル)がない場合は、次のように入力できます。

make project3

makefileをまったく使用せずにmake次のコマンドを思い付きます。

g++ -o project3 project3.cpp

この場合、正しいC ++標準が指定されていないため、このコマンドは間違っています。しかし、それはしばしば機能し、同じベース名でターゲットとソースに名前を付けるのは良い理由です。

もう1つ、ファイルtree.hはヘッダーのみのライブラリであり、問​​題ありません。しかしhelperMethods.h、ヘッダーファイルのふりをしているだけです。それは本当に完全な実装です。あなたはそれを修正する必要があります。

また、ヘッダーファイルを挿入することは本当に悪い考えです。using namespace stdヘッダーファイルは、std::名前空間プレフィックスを必要とするすべてのものに明示的に使用する必要があります。通常using namespace std、どこでも使用することはお勧めしませんが、ヘッダーを含むファイルのデフォルトの名前空間をサイレントに汚染するため、ヘッダーファイルでは特に問題があります。これは、非常にあいまいなバグやコンパイルエラーにつながる可能性があります。

于 2013-03-17T06:42:52.077 に答える
1

学校のプロジェクトですね project3あなたが自分で取り組んでいる何かのひどい恣意的な名前のようです。

厳密に言えば、.hファイルを個別にコンパイルする必要がないため、makefile処理に.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の最初のファイルが自動的に選択されることに注意してください)、中間ファイルをクリーンアップするためのルール、から実行可能ファイルをビルドするためのルールです。オブジェクトファイル、およびソースファイルからオブジェクトファイルを構築するためのルール。このアプローチはあまり拡張性がありません。より大きく、より複雑なmakefileのすべての依存関係を手動で管理するのは不快ですが、この非常に単純なケースでは問題ありません。

于 2013-03-17T06:40:29.627 に答える