Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

C++ - Jak skompilować kilka modułów?

Rhaesas 03 Lut 2013 13:43 1329 4
  • #1 03 Lut 2013 13:43
    Rhaesas
    Poziom 6  

    Witam.
    Ostatnio zacząłem uczyć się języka C++ z książki Jerzego Grębosza "Symfonia C++ standard".
    Wszystko idzie całkiem dobrze, aż do momentu kiedy muszę skompilować program składający się z dwóch modułów i pliku nagłówkowego. Pracuję na Linuxie, Ubuntu, a kompiluję g++. Wszystkie operacje w terminalu.

    Próbowałem robić tak:

    Code:
    g++ -c modul1.cpp


    Tak też próbowałem :

    Code:
    g++ modul1.cpp modul2.cpp nagl.h -o program


    I w tym momencie dostaję masę błędów wyglądających mniej więcej w tym sposób:

    Code:
    28.cpp: In function ‘void funkcja_kenijska()’:
    
    28.cpp:24:29: error: no match for ‘operator<’ in ‘(& std::operator<< [with _Traits = std::char_traits<char>]((* &(& std::operator<< [with _Traits = std::char_traits<char>]((* & std::cout), ((const char*)"Na swiecie jest ")))->std::basic_ostream<_CharT, _Traits>::operator<< [with _CharT = char, _Traits = std::char_traits<char>](ile_murzynow)), ((const char*)"murzynow, oraz ")))->std::basic_ostream<_CharT, _Traits>::operator<< [with _CharT = char, _Traits = std::char_traits<char>](ile_europejczykow) < "europejczykow \012"’
    28.cpp:24:29: note: candidates are:
    28.cpp:24:29: note: operator<(const char*, const char*) <built-in>
    28.cpp:24:29: note:   no known conversion for argument 1 from ‘std::basic_ostream<char>’ to ‘const char*’
    28.cpp:24:29: note: operator<(void*, void*) <built-in>
    28.cpp:24:29: note:   no known conversion for argument 2 from ‘const char [16]’ to ‘void*’
    /usr/include/c++/4.6/bits/stl_pair.h:207:5: note: template<class _T1, class _T2> bool std::operator<(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)
    /usr/include/c++/4.6/bits/stl_iterator.h:291:5: note: template<class _Iterator> bool std::operator<(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
    /usr/include/c++/4.6/bits/stl_iterator.h:341:5: note: template<class _IteratorL, class _IteratorR> bool std::operator<(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)




    /usr/include/c++/4.6/bits/basic_string.h:2510:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::basic_string<_CharT, _Traits, _Alloc>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
    /usr/include/c++/4.6/bits/basic_string.h:2522:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::basic_string<_CharT, _Traits, _Alloc>&, const _CharT*)
    /usr/include/c++/4.6/bits/basic_string.h:2534:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const _CharT*, const std::basic_string<_CharT, _Traits, _Alloc>&)


    Wstawię jeszcze kody programów.

    Pierwszy:

    Code:
    #include<iostream>
    
    using namespace std;
    #include "nagl.h"
    int ile_murzynow = 9;
    int main()
    {
      cout <<"Poczatek programu\n";
      funkcja_francuska();
      funkcja_niemiecka();
      cout<<"Koniec programu\n";
    }
    //*******************************************
    void funkcja_egipska()
    {
      cout <<"Jestem w Kairze!---------\n";
      cout<<"Na swiecie jest " << ile_murzynow<<"murzynow, oraz "
          << ile_europejczykow <<"europejczykow \n";
    }
    //***********************************************************
    void funkcja_kenijska()
    {
      cout <<"Jestem w Nairobi! -------\n";
      cout <<"Na swiecie jest "<<ile_murzynow<<"murzynow, oraz "
           <<ile_europejczykow <"europejczykow \n";
    }
    //*****************************************************************


    Drugi :

    Code:
    #include<iostream>
    
    using namespace std;
    #include "nagl.h"
    ile ile_europejczykow = 8;
    //*************************
    void funkcja_francuska()
    {
      cout <<"Jestem w Paryzu! ************\n";
      cout<<"Na swiecie jest "<<ile_murzynow<<"murzynow, oraz "
          <<ile_europejczykow<<"europejczykow\n";
      funkcja_egipska();
    }
    //*******************************************************
    void funkcja_niemiecka()
    {
      cout <<"Jestem w Berlinie!********\n";
      cout<<"Na swiecie jest "<<ile_murzynow<<"murzynow, oraz "
          <<ile_europejczykow<<"europejczykow\n";
      funkcja_kenijska();
    }


    Oraz plik nagłówkowy:

    Code:
    extern int ile_murzynow;
    
    extern int ile_europejczykow;
    void funkcja_egipska();
    void funkcja_niemiecka();
    void funkcja_kenijska();
    void funkcja_francuska();


    PS. Tak, wiem - jest to żywcem przepisane z książki, czego się nauczę, prawda? Później jest kolejny program do napisania, również trzeba go podzielić na moduły - wolałem wrzucić ten, prawdopodobieństwo, że znajdzie się tutaj błąd jest o wiele wiele mniejsze niż w moim ;).

    0 4
  • #2 03 Lut 2013 14:18
    michcior
    Poziom 30  

    Dobra, odpowiem krótko jak to jest a potem sobie wykorzystasz jak chcesz.

    Do zrozumienia: kompilacja przebiega dwuetapowo, najpierw kompilowane są pliki c,c++ (to co nazywasz modułami), wyniku kompilacji powstają tzw. "obiekty" (.o), są to kawałki kodu maszynowego dla każdej funkcji jaką zrobiłeś, zmiennych itd. Są one jednak "luźne" i nie tworzą całość. Powiązanie do kupy w jeden program to tzw. linkowanie czyli drugi etap. Na tym etapie jak czegoś zabraknie to będzie krzyk.

    1) można budować (build) na dwa sposoby:

    metoda 1: wszystkie pliki C,C++ listujesz w jednej linii wywołania g++ po opcji "-o" wstawiasz nazwę wynikową (jak nie podasz to dostaniesz plik "a.out").

    metoda 2: Najpierw tworzymy jawnie pliki obiektów (w met.1 też są tworzone tyle że w katalogu /tmp). Robi się to wywołując g++ dla każdego pliku c,c++ oddzielnie, podając plik z opcja -c, każde wywołanie da nam jeden obiekt. Potem dokonujemy jawnego linkowania poprzez wywołanie g++ z podaniem zamiast plików .cpp pliki .o

    2) wszystkie katalogi w których znajdują się headery podajemy do g++ poprzez opcje -I, np: "g++ -Imojeincludy -Ilibs/poco " (po -I nie ma spacji) są to ścieżki wyszukiwania headerów. Ma to sens tylko przy kompilacji. Dla linkowania bez zaczenia.

    3) Wszystkie biblioteki dodajemy poprzez ścieżki wyszukiwania bibliotek: "-Lsciezkadomoichbibliotek" a same biblioteki tak: "-lmojabiblioteka" gdzie fizycznie plik leżący w jednej z podanych ścieżek to libmojabiblioteka.a (lib jest domyślny). np, chcąc wykorzystać funkcje z biblioteki matematycznej (np. sin) trzeba do wywołania linkera dodać -lm (nie potrzeba ścieżki bo to biblioteka tak ważna że kompilator wie gdzie jej szukać :)) spowoduje to dodanie do kompilacji biblioteki /usr/lib/libm.a

    4) można podać bibliotekę jawnie w linkowaniu tak jak obiekt czyli podając pełną ścieżką pliku.

    5) biblioteki .a są niesłusznie nazywana bibliotekami, to są archiwa czyli prymitywne grupy obiektów .o. Inaczej mówiąc, grupę plików .o można scalić narzędziem "ar" do archiwum .a, dla linkera to bez znaczenia.

    6) biblioteki .so to są biblioteki dynamiczne, można je zlinkować dynamicznie, to znaczy podczas kompilacji trzeba je podać ale fizycznie nie znajdą się w naszej binarce natomiast będą musiały być dostępne podczas uruchomienia.

    7) PRZERÓB NARZĘDZIE MAKE !!!

    0
  • #3 03 Lut 2013 14:44
    Rhaesas
    Poziom 6  

    Dobrze, więc to, co wpiszę w terminal powinno wyglądać mniej więcej w ten sposób? :

    Code:
    g++ modul1.cpp modul2.cpp nagl.h -o program


    Jeżeli tak to po czymś takim nadal mam te błędy, które wypisałem w pierwszym poście.

    Dodam, że pliki znajdują się w katalogu głównym. Wcześniej trochę uczyłem się Ansi C, gdzie nie trzeba było podawać lokalizacji pliku, kiedy znajdował się w katalogu głównym. Tutaj na pewno też tak jest, prawda?

    0
  • #5 03 Lut 2013 14:55
    Rhaesas
    Poziom 6  

    Dobra, już wszystko mam. Dzięki za pomoc! ;)

    0