Компилировать несколько исходных файлов (основных и заголовочных) и связывать их в ROOT CINT?

Позвольте мне сначала установить контекст, это CERN ROOT и CINT и ACLiC и т. д.

Предположим, у меня есть основной macro с именем macro.cpp и два заголовка h1.cpp (содержит определение функции) и h1.h, содержащие объявление функции, определенной в h1.cpp, аналогично у меня есть h2.cpp и h2.h. Основная программа macro.cpp вызывает эти функции внутри h1 и h2. Мне удалось скомпилировать исходные файлы, используя:

   root [0] .L h1.cpp+
   root [1] .L h2.cpp+
   root [2] .L macro.cpp+

который сгенерировал три файла .so macro_cpp.so, h1_cpp.so и h2_cpp.so. Я хочу знать, что с ними делать? Как мне link их так, чтобы у меня было что-то вроде "macro.out" или что-то в этом роде (один файл executable какого-то вида), который я могу выполнить (хотя я не знаю, как!) и добиться всего, чего я хотел достичь с помощью макрос.

Примечание. Если я просто загружу все файлы, используя .L file_name.cpp и т. д., и просто выполню основной макрос, используя .x macro.cpp, тогда все будет работать нормально, и у меня будут результаты, но это не то, что мне нужно! Я хочу скомпилировать как мы в обычном g++ и кстати на каждом форуме все советуют компилировать с помощью .L file_name.cpp+ или ++.. Очень хотелось бы узнать всю историю. Потому что кроме .L file_name.cpp+ никто ничего не объясняет... что дальше? Что делать с .so и т.д.

Я новичок, я буду очень признателен за простой и пошаговый ответ и объяснение.

Спасибо.

Edit-1: я работаю с:

g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

Редактировать-2: Информация, связанная с ROOT: ROOT 5.34/36 (v5-34-36@v5-34-36, 07 декабря 2016 г., 23:31:51 на linuxx8664gcc ) Интерпретатор CINT/ROOT C/C++, версия 5.18.00, 2 июля 2010 г.


person quanta    schedule 04.01.2017    source источник
comment
.so — это динамически подключаемая библиотека, такая как .dll в Windows. Короче говоря, это скомпилированный код, который может использоваться несколькими программами. Вы можете использовать команду оболочки: ldd ./myprogram, чтобы увидеть все .so, необходимые вашей программе.   -  person baddger964    schedule 04.01.2017
comment
так как вы спрашиваете, что дальше?: после .L macro.cpp+ вы можете выполнять функции, которые определены в этом файле, например .L macro.cpp+; macro(3.1415);. сохраненный .so будет прочитан при следующем выполнении .L macro.cpp+ (без перекомпиляции уже скомпилированных макросов). или вы можете просто загрузить ранее скомпилированные файлы .so с помощью gSystem->Load("macro_C.so");.   -  person pseyfert    schedule 05.01.2017
comment
@pseyfert это замечательно.   -  person quanta    schedule 05.01.2017


Ответы (2)


Если вы хотите скомпилировать и связать, вы можете использовать стандартный компилятор вместо Cint/Aclic. Например, предполагая, что вы работаете на платформе *nix, вы можете использовать приведенные ниже примеры файлов:

h1.h

int add_one(int a);

h1.cpp

#include "h1.h"

int add_one(int a)
{
    return a+1;
}

h2.h

#include <TLorentzVector.h>

TLorentzVector multiply_by_two(const TLorentzVector v);

h2.cpp

#include "h2.h"

TLorentzVector multiply_by_two(const TLorentzVector v)
{
    return 2.0*v;
}

macro.cpp

#include "h1.h"
#include "h2.h"

#include <TLorentzVector.h>

#include <iostream>
using std::cout;
using std::endl;

int main()
{
    int a = 0;
    TLorentzVector v;
    v.SetPtEtaPhiM(1.0, 0.0, 0.0, 0.0);
    cout<<"calling add_one on "<<a<<": "<<add_one(a)<<endl;
    cout<<"calling multiply_by_two on "<<v.Pt()<<": "<<multiply_by_two(v).Pt()<<endl;
    return 0;
}

Затем вы можете скомпилировать с

g++ -c -g -Wall `root-config --cflags` h1.cpp
g++ -c -g -Wall `root-config --cflags` h2.cpp
g++ -c -g -Wall `root-config --cflags` macro.cpp

и связать с

g++ `root-config --glibs` h1.o h2.o macro.o

Исполняемый файл будет a.out:

$ ./a.out 
calling add_one on 0: 1
calling multiply_by_two on 1: 2

Вы можете поместить эти g++ команд в сценарий или, когда у вас появится несколько файлов и каталогов, вы можете написать свой make-файл (или cmake). Для этого последнего шага см., например, учебник здесь

http://www-pnp.physics.ox .ac.uk/~brisbane/Teaching/Makefiles/Tutorial

int add_one(int a);
Makefiles_and_ROOT.pdf

Примечание 1: одним из преимуществ использования g++ является то, что вы будете получать четкие сообщения об ошибках, когда что-то не компилируется. Сообщения об ошибках от Cint могут быть трудными для понимания, хотя это значительно улучшено в root 6 с помощью Cling.

Примечание 2: еще одно преимущество использования стандартного компилятора заключается в том, что вы сможете легко связать свой основной исполняемый файл с библиотеками, отличными от root.

person user2148414    schedule 05.01.2017
comment
Я согласен с использованием g++, а не cint/aclic. На самом деле я знаю, как связать обычные источники C ++, которые не включают корневые библиотеки, из вашего ответа теперь я знаю, как связать корневые библиотеки. Я постараюсь и вернусь. Однако проблема с main заключается в том, что я не могу передать имя файла ROOT и другие параметры во время самого выполнения, поскольку main, я думаю, не принимает таких аргументов. Предположим, что macro похоже на void macro(TString filename, Int_t nbin), как это меняет дело? - person quanta; 05.01.2017
comment
Я, конечно, могу изменить макрос на main, как это сделали вы, а затем на std::cin>>filename и т. д. Это тоже сработает... но спрашивайте иначе, просто ради знаний. - person quanta; 05.01.2017
comment
команда связывания g++ root-config --glibs` h1.o h2.o macro.o` выдает много ошибок (возможно, что-то связанное с TLorentzVector и корневым путем включения), которые я не могу разместить в одном комментарии, поэтому публикую в нескольких (следующие) комментарии: - person quanta; 05.01.2017
comment
h2.o: In function __static_initialization_and_destruction_0(int, int)': /home/me/root/include/TVersionCheck.h:34: неопределенная ссылка на TVersionCheck::TVersionCheck(int)' h2.o: In function operator*(double, TLorentzVector const&)': /home/me/root/include/TLorentzVector.h:596 : неопределенная ссылка на TLorentzVector::TLorentzVector(double, double, double, double)' macro.o: In function main': /home/me/macro.cpp:13: неопределенная ссылка на TLorentzVector::TLorentzVector()' /home/me/macro.cpp:16: undefined reference to TLorentzVector::TLorentzVector(TLorentzVector const&)'` - person quanta; 05.01.2017
comment
/home/me/macro.cpp:16: undefined reference to TLorentzVector::~TLorentzVector()' /home/me/macro.cpp:16: неопределенная ссылка на TLorentzVector::~TLorentzVector()' /home/me/macro.cpp:13: undefined reference to TLorentzVector::~TLorentzVector()' /home/me/macro.cpp:16: неопределенная ссылка на TLorentzVector::~TLorentzVector()' /home/me/macro.cpp:16: undefined reference to TLorentzVector::~TLorentzVector( )'` - person quanta; 05.01.2017
comment
macro.o:/home/macro.cpp:13: more undefined references to TLorentzVector::~TLorentzVector()' следуйте макросу.o: В функции __static_initialization_and_destruction_0(int, int)': /home/me/root/include/TVersionCheck.h:34: undefined reference to TVersionCheck::TVersionCheck(int)' macro.o: В функции TLorentzVector::Perp() const': /home/me/root/include/TLorentzVector.h:421: undefined reference to TVector3::Perp() const' collect2: ошибка: ld вернул 1 статус выхода` - person quanta; 05.01.2017
comment
с root-config --libs вы получаете не все корневые библиотеки (или их команды связи), а только основные (те, которые всегда нужны). (и аналогично для --glibs, посмотрите на root-config --help разницу). - person pseyfert; 05.01.2017
comment
В вашем случае вам нужно добавить -lPhysics после вызова root-config: $(root-config --libs) -lPhysics. Как я узнал: grep TLorentzVector $(root-config --libdir)/*.rootmap (в файлах *.rootmap по сути указано, какой класс находится в какой стандартной корневой библиотеке. Библиотеки и файлы корневой карты находятся в каталоге root-config --libdir. Файлы корневой карты являются открытым текстом. - person pseyfert; 05.01.2017
comment
@pseyfert g++ ни root-config --glibs` -lPhysics h1.o h2.o macro.o` nor root-config --glibs -lPhysics` h1.o h2.o macro.o` не работали! - person quanta; 05.01.2017
comment
с той же ошибкой (отсутствуют вещи TLorentzVector)? $(root-config --libdir)/libPhysics.so существует? при выполнении nm -C libPhysics.so вы должны видеть, что находится внутри этой библиотеки. так что вы можете проверить, есть ли внутри нужные вам вещи TLorentzVector (особенно методы, на которые жалуется ваш компоновщик). - person pseyfert; 06.01.2017
comment
Да, ошибка все та же, и библиотека libPhysics.so существует. - person quanta; 06.01.2017
comment
Я бы посоветовал вам использовать argc и argv для передачи ваших аргументов и параметров (см., например, этот вопрос на переполнение стека/3024197. - person user2148414; 06.01.2017
comment
Что касается ошибок, которые вы видите при связывании: @pseyfert прав, в зависимости от заголовков, которые вы включаете, вам может потребоваться добавить некоторые библиотеки вручную. Какую версию рута вы используете? Например, с корнем 6.04/06 у меня есть ``$ root-config --glibs -L/usr/lib/root -lGui -lCore -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread -pthread -lm -ldl -rdynamic ``` Библиотека указана в правом верхнем углу веб-страницы документа - person user2148414; 06.01.2017
comment
редактировать: верхний левый угол документа. Например, для TLorentzVector см. здесь - person user2148414; 06.01.2017
comment
Я попробовал это: g++ main.cpp h1.cpp h2.cpp `root-config --libs --cflags` -o main.o, и я думаю, что это сработало и создало main.o как исполняемый файл, ./main.o произвело calling add_one on 0: 1 calling multiply_by_two on 1: 2 - person quanta; 06.01.2017
comment
Одношаговое g++ main.cpp ... -o main.o также является допустимым решением. Я предложил два отдельных шага компиляции + компоновки, потому что это, похоже, было просьбой в начальном посте. К сожалению, я не могу воспроизвести ошибку, которую вы наблюдаете, даже при использовании корневой версии, близкой к той, которую вы указали (root 5.34/25, g++ 4.8.1). Для справки: в этой версии библиотеки, указанные в libPhysics.rootmap, являются -lMatrix -lPhysics -lMathCore, которые действительно появляются в списке, созданном root-config --glibs. - person user2148414; 07.01.2017
comment
Не могли бы вы обновить точную команду, которую вы используете для связывания файлов .o? У вас работает только g++ `root-config --glibs` h1.o h2.o macro.o без ошибок? Мне интересно, почему эта единственная команда g++ main.cpp h1.cpp h2.cpp `root-config --libs --cflags` -o main.o компилируется без ошибок, а для другой нужны спецификации библиотеки. Я новичок, будет здорово, если вы поделитесь своей полной командой компоновки для этого точного примера и, пожалуйста, укажите, включаете ли вы больше корневых заголовков. Спасибо. - person quanta; 07.01.2017
comment
Это именно те команды, которые я использовал: g++ -c -g -Wall `root-config --cflags` h1.cpp g++ -c -g -Wall `root-config --cflags` h2.cpp g++ -c -g -Wall `root-config --cflags` macro.cpp g++ `root-config --glibs` h1.o h2.o macro.o или альтернативно g++ macro.cpp h1.cpp h2.cpp `root-config --libs --cflags` -o main.o - person user2148414; 09.01.2017
comment
Команды root-config расширяются до --cflags : -pthread -m64 -I/usr/include/root --glibs : -L/usr/lib64/root -lGui -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread -pthread -lm -ldl -rdynamic с использованием той же версии 5.34/36. Вы установили root из исходного кода или установили его как пакет Ubuntu? root-config --features может указать, какие функции были включены при создании root. - person user2148414; 09.01.2017
comment
@user2148414 user2148414 извините, что не вернулся раньше. Я установил root из исходников. Я думаю, что моя установка завершена и проблем с библиотекой нет, я говорю это, потому что g++ macro.cpp h1.cpp h2.cpp root-config --libs --cflags -o main.o этот метод решил мою проблему, и с тех пор я создал гораздо более сложные приложения, включающие так много корневых объектов, и компилятор вообще не жаловался. Ваш ответ и комментарии дали мне направление к этому однострочному решению, и я хотел бы написать ответ, предназначенный для будущего новичка, надеюсь, никто не возражает. Большое спасибо. - person quanta; 11.01.2017
comment
@user2148414 user2148414 Прошу вас прочитать мое обновление (stackoverflow.com/a/41580377/4962474) и прокомментировать, если вы хочется, конечно. Большое спасибо. - person quanta; 11.01.2017

Этот ответ в основном основан на ответе user2148414, но если вы последуете ответу, то заметите, что были некоторые проблемы с способ связывания исходных (*.cpp) файлов. Мой ответ также касается другого важного объекта, называемого TApplication, который будет играть решающую роль в таких приложениях, использующих корневые библиотеки. Следующий шаг связывания:

g++ `root-config --glibs` h1.o h2.o macro.o

вероятно, покажет много ошибок, жалующихся на корневые объекты, такие как TWhatever (в ответе user2148414 TLorentzVector покажет проблемы). В комментариях к этому ответу можно найти обсуждение включения различных физических библиотек, которые могут решить проблему, но без обсуждения этого (и мне тоже неудобно :) ) позвольте мне написать команду, которая решает все.

Эта процедура является однострочной, поэтому нет необходимости компилировать отдельные файлы, создавать файлы *.cpp и файлы *.h, как описано в . этот ответ затем скомпилируйте и свяжите и создайте один исполняемый файл с именем «someExecutable», используя:

g++ macro.cpp h1.cpp h2.cpp `root-config --libs --cflags` -o someExecutable

или лучше (и это нужно делать)

g++ -Wall -Wextra -Werror -pedantic -std=c++14 macro.cpp h1.cpp h2.cpp `root-config --libs --cflags` -o someExecutable

Это решит мой первоначальный ответ, но для полноты я хотел бы добавить еще несколько вещей.

TПриложение

Моей первоначальной мотивацией было создать приложение, которое взаимодействует с "ROOT", но я не хотел работать с оболочка ROOT, CINT, ACLiC и т. д., и хотел полностью работать с g++. user2148414, и мой ответ решит часть создания приложения, но приложение не будет служить никакой цели, оно будет работать , создайте гистограммы, нарисуйте их и сделайте все остальное, но все холсты в конце концов закроются, когда код достигнет «return 0;». Чтобы холсты оставались открытыми, нам понадобится «TApplication». Итак, учитывая main ответа user2148414, я включу еще две строки и включу два аргумента в main :

macro.cpp

    #include "h1.h"
    #include "h2.h"

    #include <TLorentzVector.h>

    #include <iostream>
    using std::cout;
    using std::endl;

    int main(int argc, char* argv[])  //introduced arguments to main
    {

     // here I introduce TApplication

   TApplication* SomeApp = new TApplication("SomeApp",&argc, argv); 

        int a = 0;
        TLorentzVector v;
        v.SetPtEtaPhiM(1.0, 0.0, 0.0, 0.0);
        cout<<"calling add_one on "<<a<<": "<<add_one(a)<<endl;
        cout<<"calling multiply_by_two on "<<v.Pt()<<": "<<multiply_by_two(v).Pt()<<endl;

        //and just before returning 0
         SomeApp->Run();

        return 0;
    }
person quanta    schedule 10.01.2017