2013-03-17 2 views
0

У меня возникли проблемы с созданием make-файла для проекта, содержащего 3 файла C++.Непонятно, как создать 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 project3 tree.h helperMethods.h main.cpp действительно компилировать три файла и сделать исполняемый файл, который работает на нем должен.

После этого я сохраняю make-файл, выхожу из emacs и пытаюсь запустить его.

Сначала я использовал сделать но вернулся:

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

Затем я попытался с помощью сделать -f makefile.make, но это не сработало, и вернулся:

make: Nothing to be done for `all'. 

На данный момент я не уверен, почему make-файл не был создан должным образом. У меня нет большого опыта работы с make-файлами; Я уверен, что у меня есть правильные команды в тексте 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 ** для проблем, с которыми вы сталкиваетесь с make-файлами, вероятно, поможет вам в решении проблемы. Если выше, на самом деле, весь ваш Makefile, я предлагаю вам провести какое-то серьезное время с [gnu make online documentation] (http://www.gnu.org/software/make/manual/). – WhozCraig

+0

BTW, для сложного 'Makefile'-s, вы можете установить вместо него' remake' вместо 'make' (они совместимы), особенно с флагом' -x' для 'remake' –

+0

Еще одно примечание о стиле: общий практика заключается в размещении определений в файлах .cpp и декларациях (т. е. просто прототипах функций, определениях классов и т. д.) в файлах заголовков. – Wug

ответ

3

Makefiles обычно называют Makefile (хотя makefile работ тоже) без какого-либо расширения. Если вы используете расширение (не рекомендуется), вы должны указать make имя файла makefile. Это утомительно и не нужно.

Во-вторых, вам не нужно помещать файлы заголовков в командную строку компиляции, и вы не должны этого делать. Вы используете строки #include в своем файле, чтобы указать файлы заголовков. Так что ваша команда компиляции может выглядеть следующим образом:

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

Теперь, в этой команде:

  • main.cpp является источник

  • project3 является целевой (т.е. файл, который будет создан.)

также:

  • tree.h и helperMethods.h необходимы для компиляции для работы; компиляция зависит от файлов. (Вы знаете это, но они не отображаются в командной строке, поэтому это не очевидно.) Кроме того, если они меняются, вам нужно перекомпилировать ваш файл.

файл сборка объясняет, как сделать цели из своих источников, а также перечислены зависимости от мишени. (Технически сделать не различает источников и зависимостей;.. Он считает, как из них предпосылки Но это удобно распознавать разницу)

Таким образом, для указанной выше команды, весь сделанный рецепт может выглядеть следующим образом:

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.o из main.cpp, а затем правило для создания исполняемого файла из 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 для этой цели. В этом процессе есть определенная степень свободы.

У вас есть правило, чтобы построить все это (имея в виду, что если цель не указана, первый в make-файле автоматически выбирается), правила для очистки любых промежуточных файлов, правила для сборки исполняемый файл из объектных файлов и правило для создания объектного файла из исходных файлов.Такой подход не очень хорошо масштабируется; было бы неприятно управлять вручную всеми зависимостями для более крупных, более сложных make-файлов, но в этом очень простом случае это нормально.

Смежные вопросы