Как я могу сделать мой высокомодульный проект легким для конечных пользователей для компиляции? - PullRequest
5 голосов
/ 05 марта 2011

Я работаю над относительно большим набором библиотек C-кода с последовательным кодом, которые затем будут распараллеливаться в CUDA моими сотрудниками.

Для этого проекта мой код сводится к

#include "Initialize.cpp"
#include "PerformMoves.cpp"
#include "CollectResults.cpp"

main() 
{
   //DECLARE General Vars

   Initialize();

   for (unsigned int step=0; step < maxStep; step++)
   {
      PerformMoves();
   }

   CollectResults();
}

Теперь шаги, которые я выполняю в Initialize и PerformMoves, будут сильно отличаться в зависимости от того, какую симуляцию я создаю. Скорость - это максимальная производительность, так как мой код представляет собой симуляцию Монте-Карло, которая будет выполнять миллионы ходов, каждый из которых предполагает потенциально тысячи вычислений. Таким образом, я хочу избежать ненужных условий.

Таким образом, я, по сути, хочу разные модули C "включай и работай", например,

InitializeSimType1.cpp InitializeSimType2.cpp InitializeSimType3.cpp

PerformMovesType1.cpp PerformMovesType2.cpp PerformMovesType3.cpp

....

Каждый оптимизирован для определенного типа процедуры моделирования, без "пуха" больших условных выражений для обработки множества случаев.

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

g ++ Main.cc Initialize.cpp PerformMoves.cpp CollectResults.cpp -o MC_Prog

Я хотел бы перейти к какой-то схеме условной компиляции, где у меня есть какой-то конфигурационный файл сортировки, где я указываю опции, и он берет правильные файлы cpp и компилирует их.

Я бы предположил, что makefile + config файлы - моя лучшая ставка, но помимо базовых целей и очень линейной компиляции я довольно новичок в мире сложных make-файлов.

Какими хорошими способами я мог бы создать систему компиляции на основе списка, которая позволила бы пользователям с базовыми знаниями C легко создавать цели с помощью модулей, которые они хотят. Мои конечные пользователи не будут обладать большими знаниями по make-файлам (или знаниями по программированию в целом), поэтому о сложной системе с их стороны не может быть и речи. Я хочу, чтобы они в основном имели прозрачную систему, управляемую файлами конфигурации, которая позволит им выбрать один модуль Initialize, один модуль PerformMoves и один модуль CollectResults. После того, как они изменили этот файл конфигурации своими выборами, я хочу, чтобы они могли выполнять компиляцию одной командой.

Другими словами, я хочу иметь возможность создавать README, который направляет пользователей:

  1. Введите эти записи в этот файл конфигурации (дает имя файла конфигурации, опции для каждой записи файла конфигурации) ...
  2. Компилировать с помощью этой команды (дает одну команду)

Я знаю, что это довольно абстрактный и сложный вопрос, но я знаю, что есть некоторые эксперты по Makefile / c, которые могли бы предложить мне хорошее руководство.

1 Ответ

1 голос
/ 05 марта 2011

Я могу вспомнить пару похожих систем сборки:

  1. Когда вы собираете GCC, он создает библиотеки с помощью вспомогательных процедур (например, libgcc.a). Он хочет убедиться, что только необходимые функции связаны с вашей программой. Поскольку единица гранулярности - один .o, он строит один .c файл десятки раз с различными вариантами -D_enable_xxx, чтобы включить каждую функцию по отдельности. Затем он использует ar, чтобы превратить полученный .o в .a, с которым вы можете связать, чтобы получить только то, что вам нужно.
  2. Сервер X Window имеет несколько функций, которые выполняют практически идентичные операции, за исключением того, что математика в самом внутреннем цикле отличается. Например, это может быть xor или and или or битов вместе. Ему также не нужны условные выражения во внутреннем цикле, поэтому он снова и снова строит один и тот же файл с различными опциями -D_math_xor, чтобы получить десятки .o, каждая из которых имеет одну функцию, которая выполняет специальную математическую операцию, заключенную в функцию цикла. Он использует все .o (поскольку операция на самом деле выбирается клиентом X, а не во время компиляции), поэтому метод .a не важен.

Звучит так, как будто вы можете использовать их комбинацию для создания библиотеки .o, где каждая из них предварительно компилируется с вашими конкретными параметрами, а затем перестраивается просто main.c снова и снова, вызывая различные функции и связываясь с вашей библиотекой .

Основываясь на ваших комментариях ниже, вот еще несколько идей:

  1. Когда вы собираете binutils, GCC, glibc и т. Д., Вы распаковываете дистрибутив исходного кода, но вы не строите внутри дерева исходных текстов . Вместо этого вы mkdir obj-mytarget; cd obj-mytarget; ../path/to/gcc/configure --options...; make Сценарий configure создает config.h и Makefile, специфичные для параметров (и, конечно, для системных возможностей). Одним из больших преимуществ этой настройки является то, что все продукты сборки (от .o до исполняемых файлов) для этого набора параметров являются автономными и не мешают сборкам с использованием других параметров.
  2. Классическая конфигурация ядра BSD выполняется путем редактирования файла (идиоматически получая имя всех заглавных букв, например GENERIC, которое создает ядро ​​по умолчанию, или LINT, которое включает все для статического анализа), а затем вызывает config CONFNAME. config анализирует простой файл конфигурации и создает дерево каталогов, названное по имени файла. Дерево каталогов содержит Makefile и различные .h файлы для управления сборкой. Те же основные преимущества, что и для описанного выше метода.
  3. avr-libc (библиотека для микроконтроллеров Atmel AVR) автоматизирует вышеуказанные подходы, автоматически создавая целевые каталоги для десятков микроконтроллеров (с изменениями в объеме памяти, доступности периферийных устройств и т. Д.) И собирая все всех вариации за один проход. В результате появилось много библиотек, предоставляющих кросс-среду сборки, способную ориентироваться на любой AVR. Вы можете использовать аналогичную идею для автоматического построения каждой перестановки вашей программы.
...