- •Оглавление
- •Об авторе
- •Благодарности
- •Предисловие
- •Глава 1. Держим оборону
- •На пути к хорошему коду
- •Готовьтесь к худшему
- •Что такое защитное программирование?
- •Этот страшный, ужасный мир
- •Технологии защитного программирования
- •Выберите хороший стиль кодирования и пользуйтесь крепкой архитектурой
- •Пишите код без спешки
- •Не верьте никому
- •Стремитесь к ясности, а не к краткости
- •Не позволяйте никому лезть туда, где ему нечего делать
- •Включайте вывод всех предупреждений при компиляции
- •Пользуйтесь средствами статического анализа
- •Применяйте безопасные структуры данных
- •Проверяйте все возвращаемые значения
- •Аккуратно обращайтесь с памятью (и другими ценными ресурсами)
- •Инициализируйте все переменные там, где вы их объявили
- •Объявляйте переменные как можно позже
- •Пользуйтесь стандартными средствами языка
- •Пользуйтесь хорошими средствами регистрации диагностических сообщений
- •Выполняйте приведение типов с осторожностью
- •Подробности
- •Ограничения
- •Какие ограничения налагать
- •Снятие ограничений
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 2. Тонкий расчет
- •Да в чем проблема?
- •Знайте своих клиентов
- •Что такое хорошее представление?
- •Размещение скобок
- •Скобки в стиле K&R
- •Расширенный стиль скобок
- •Стиль Уайтсмита (с отступами)
- •Другие стили скобок
- •Единственно верный стиль
- •Внутрифирменные стили (и когда их придерживаться)
- •Установка стандарта
- •Религиозные войны?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 3. Что в имени тебе моем?
- •Зачем нужны хорошие имена?
- •Каким объектам мы даем имена?
- •Игра в названия
- •Описательность
- •Техническая корректность
- •Идиоматичность
- •Тактичность
- •Технические подробности
- •Имена переменных
- •Имена функций
- •Имена типов
- •Пространства имен
- •Имена макросов
- •Имена файлов
- •Роза пахнет розой
- •Соблюдайте единообразие
- •Связывайте имя с содержимым
- •Извлекайте выгоду из выбора имени
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 4. Литературоведение
- •Самодокументируемый код
- •Техника написания самодокументируемого кода
- •Пишите простой код с хорошим форматированием
- •Выбирайте осмысленные имена
- •Разбивайте код на самостоятельные функции
- •Выбирайте содержательные имена типов
- •Применяйте именованные константы
- •Выделяйте важные фрагменты кода
- •Объединяйте взаимосвязанные данные
- •Снабжайте файлы заголовками
- •Правильно обрабатывайте ошибки
- •Пишите осмысленные комментарии
- •Практические методологии самодокументирования
- •Грамотное программирование
- •Инструментарий документирования
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 5. Заметки на полях
- •Что есть комментарий в коде?
- •Как выглядят комментарии?
- •Сколько комментариев требуется?
- •Что помещать в комментарии?
- •Не нужно описывать код
- •Не подменяйте код
- •Как сделать комментарии полезными
- •Не отвлекаться
- •На практике
- •Замечание об эстетичности
- •Единообразие
- •Четкие блочные комментарии
- •Отступы в комментариях
- •Комментарии в конце строки
- •Помощь в чтении кода
- •Стиль должен обеспечивать легкость сопровождения
- •Границы
- •Флажки
- •Комментарии в заголовке файла
- •Работа с комментариями
- •Помощь при написании программ
- •Заметки об исправлении ошибок
- •Устаревание комментариев
- •Сопровождение и бессодержательные комментарии
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 6. Людям свойственно ошибаться
- •Откуда что берется
- •Механизмы сообщения об ошибках
- •Без обработки ошибок
- •Возвращаемые значения
- •Переменные, содержащие состояние ошибки
- •Исключения
- •Сигналы
- •Обнаружение ошибок
- •Обработка ошибок
- •Когда обрабатывать ошибки
- •Варианты реагирования
- •Последствия для кода
- •Подымаем скандал
- •Управление ошибками
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 7. Инструментарий программиста
- •Что такое инструмент программирования?
- •А зачем они нужны – инструменты?
- •Электроинструменты
- •Выясните, каковы его возможности
- •Научитесь им управлять
- •Выясните, для каких задач он пригоден
- •Убедитесь, что он работает
- •Имейте четкие данные о том, как получить дополнительные сведения
- •Узнайте, как получить новые версии
- •Какой инструмент необходим?
- •Средства редактирования исходного кода
- •Средства построения кода
- •Инструменты для отладки и тестирования
- •Средства поддержки языка
- •Инструменты различного назначения
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 8. Время испытаний
- •Проверка на подлинность
- •Кто, что, когда, зачем?
- •Зачем тестировать
- •Кому тестировать
- •В чем состоит тестирование
- •Когда тестировать
- •Типы тестирования
- •Выбор контрольных примеров для блочного тестирования
- •Архитектура и тестирование
- •Руками не трогать!
- •Анатомия провала
- •Справлюсь ли я сам?
- •Система контроля ошибок
- •Обсуждение ошибок
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 9. Поиск ошибок
- •Реальные факты
- •Природа этого зверя
- •Взгляд с высоты птичьего полета
- •Взгляд с поверхности земли
- •Взгляд из глубины
- •Борьба с вредителями
- •Обходная дорога
- •Правильный путь
- •Охота за ошибками
- •Ошибки этапа компиляции
- •Ошибки этапа исполнения
- •Как исправлять ошибки
- •Профилактика
- •Отладчик
- •Средство проверки доступа к памяти
- •Трассировщик системных вызовов
- •Дамп памяти
- •Журналирование
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 10. Код, который построил Джек
- •Языковые барьеры
- •Интерпретируемые языки
- •Компилируемые языки
- •Делаем слона из мухи
- •Выполнение сборки
- •Что должна уметь хорошая система сборки?
- •Простота
- •Единообразие
- •Повторяемость и надежность
- •Атомарность
- •Борьба с ошибками
- •Механика сборки
- •Выбор целей
- •Уборка
- •Зависимости
- •Автоматическая сборка
- •Конфигурация сборки
- •Рекурсивное применение make
- •Мастер на все руки
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 11. Жажда скорости
- •Что такое оптимизация?
- •От чего страдает оптимальность кода?
- •Доводы против оптимизации
- •Альтернативы
- •Нужна ли оптимизация
- •Технические подробности
- •Убедитесь, что нужна оптимизация
- •Определите самую медленную часть кода
- •Тестирование кода
- •Оптимизация кода
- •После оптимизации
- •Методы оптимизации
- •Конструктивные изменения
- •Модификация кода
- •Как писать эффективный код
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 12. Комплекс незащищенности
- •Риски
- •Наши оппоненты
- •Оправдания, оправдания
- •Ощущение незащищенности
- •Опасный проект и архитектура
- •Переполнение буфера
- •Встроенные строки запросов
- •Условия гонки
- •Целочисленное переполнение
- •Дела защитные
- •Технология установки системы
- •Технология конструирования программного обеспечения
- •Технологии реализации кода
- •Технологии процедуры
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 13. Важность проектирования
- •Программирование как конструкторская работа
- •Что нужно проектировать?
- •Хороший проект программного продукта
- •Простота
- •Элегантность
- •Модульность
- •Хорошие интерфейсы
- •Расширяемость
- •Избегайте дублирования
- •Переносимость
- •Идиоматичность
- •Документированность
- •Как проектировать код
- •Методы и процедуры проектирования
- •Инструменты проектирования
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 14. Программная архитектура
- •Что такое программная архитектура?
- •План программы
- •Точки зрения
- •Где и когда этим заниматься?
- •Для чего она применяется?
- •Компоненты и соединения
- •Какими качествами должна обладать архитектура?
- •Архитектурные стили
- •Без архитектуры
- •Многоуровневая архитектура
- •Архитектура с каналами и фильтрами
- •Архитектура клиент/сервер
- •Компонентная архитектура
- •Каркасы
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 15. Программное обеспечение – эволюция или революция?
- •Гниение программного обеспечения
- •Тревожные симптомы
- •Как развивается код?
- •Вера в невозможное
- •Как с этим бороться?
- •Как писать новый код
- •Сопровождение существующего кода
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 16. Кодеры
- •Мартышкин труд
- •Нетерпеливый
- •Кодер (Code Monkey)
- •Гуру
- •Псевдогуру
- •Высокомерный гений
- •Ковбой
- •Плановик
- •Ветеран
- •Фанатик
- •Монокультурный программист
- •Лодырь
- •Руководитель поневоле
- •Идеальный программист
- •И что из этого следует?
- •Для глупцов
- •Резюме
- •План действий
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 17. Вместе мы – сила
- •Команды – общий взгляд
- •Организация команды
- •Методы управления
- •Разделение ответственности
- •Организация и структура кода
- •Инструменты для групповой работы
- •Болезни, которым подвержены команды
- •Вавилонская башня
- •Диктатура
- •Демократия
- •Большой Каньон
- •Зыбучие пески
- •Лемминги
- •Личное мастерство и качества, необходимые для работы в команде
- •Общение
- •Скромность
- •Разрешение конфликтов
- •Обучение и приспособляемость
- •Знание пределов своих возможностей
- •Принципы групповой работы
- •Коллективное владение кодом
- •Нормы кодирования
- •Определите, что считать успехом
- •Установите ответственность
- •Избегайте истощения
- •Жизненный цикл команды
- •Создание команды
- •Рост команды
- •Групповая работа
- •Роспуск команды
- •Резюме
- •План действий
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 18. Защита исходного кода
- •Управление версиями исходного кода
- •Контроль версий
- •Контроль доступа
- •Работа с хранилищем
- •Пусть растут деревья
- •Краткая история систем контроля за исходным кодом
- •Управление конфигурацией
- •Резервное копирование
- •Выпуск исходного кода
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 19. Спецификации
- •Что же это такое, конкретно?
- •Типы спецификаций
- •Спецификация требований
- •Функциональная спецификация
- •Спецификация системной архитектуры
- •Спецификация интерфейса пользователя
- •Проектная спецификация
- •Спецификация тестирования
- •Что должны содержать спецификации?
- •Процесс составления спецификаций
- •Почему мы не пишем спецификации?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Когда проводить рецензирование?
- •Нужно ли рецензировать
- •Какой код рецензировать
- •Проведение рецензирования кода
- •Рецензирование на собраниях
- •Интеграционное рецензирование
- •Пересмотрите свое отношение
- •Позиция автора
- •Позиция рецензента
- •Идеальный код
- •За пределами рецензирования кода
- •Резюме
- •Контрольный список
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 21. Какой длины веревочка?
- •Выстрел в темноте
- •Почему трудно делать оценки?
- •Под давлением
- •Практические способы оценки
- •Игры с планами
- •Не отставай!
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 22. Рецепт программы
- •Стили программирования
- •Структурное программирование
- •Функциональное программирование
- •Логическое программирование
- •Рецепты: как и что
- •Процессы разработки
- •Каскадная модель
- •SSADM и PRINCE
- •Создание прототипов
- •Итеративная и инкрементная разработка
- •Спиральная модель
- •Другие процессы разработки
- •Спасибо, хватит!
- •Выбор процесса
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 23. За гранью возможного
- •Программирование приложений
- •Коробочные продукты
- •Заказные приложения
- •Программирование игр
- •Системное программирование
- •Встроенное программное обеспечение
- •Программирование масштаба предприятия
- •Численное программирование
- •И что дальше?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 24. Что дальше?
- •Но что же дальше?
- •Ответы и обсуждение
- •Глава 1. Держим оборону
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 2. Тонкий расчет
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 3. Что в имени тебе моем?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 4. Литературоведение
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 5. Заметки на полях
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 6. Людям свойственно ошибаться
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 7. Инструментарий программиста
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 8. Время испытаний
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 9. Поиск ошибок
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 10. Код, который построил Джек
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 11. Жажда скорости
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 12. Комплекс незащищенности
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 13. Важность проектирования
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 14. Программная архитектура
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 15. Программное обеспечение – эволюция или революция?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 16. Кодеры
- •Вопросы для размышления
- •Глава 17. Вместе мы – сила
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 18. Защита исходного кода
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 19. Спецификации
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 20. Рецензия на отстрел
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 21. Какой длины веревочка?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 22. Рецепт программы
- •Вопросы для размышления
- •Глава 23. За гранью возможного
- •Вопросы для размышления
- •Вопросы личного характера
- •Библиография
- •Алфавитный указатель
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Делаемm |
слона из мухи |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
243Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Распространено заблуждение, что байт%коды выполняются обязатель# но медленнее, чем соответствующие откомпилированные двоичные модули. Это не всегда так. JIT%оптимизатор может принимать разум% ные решения относительно того, какой код может значительно уско% рить его работу (например, подстраиваясь под конкретную аппарат% ную часть, на которой выполняется программа).
Будучи компромиссным решением, байт%компиляторы частично насле% дуют как преимущества, так и недостатки других подходов. Байт%код может выполняться на любой платформе, на которую перенесена вирту% альная машина, поэтому достигается переносимость ПО (хотя степень охвата разных платформ системами исполнения зависит от языка).
Делаем слона из мухи
Модели компиляции (и компиляции в байт%коды) сложнее всего в об% суждении, поэтому рассмотрим, что включает в себя компиляция про% граммного обеспечения. Просто поразительно, как мало начинающих программистов действительно понимает это, поэтому мы начнем с ба% зовых принципов. Если эта тема вам знакома, можете пропустить ее.
Для того чтобы лучше понять суть, лучше рассмотреть каждую руч% ную операцию, а не рассчитывать, что IDE выполнит за вас всю работу сборки. Все должно стать понятным из следующего рассказа в пяти частях о разработке простой программы:
1.Вы начинаете новый проект на C. Он избавит от всех невзгод, свя% занных с разработкой программного обеспечения, и откроет новую эру мирового сотрудничества. Однако единственное, что у вас вна% чале имеется, – это один файл, содержащий main. Надо же с чего%то начинать.
Собрать и запустить эту программу из одного файла легко – просто вводите compiler main.c,1 и он выплевывает исполняемый модуль, который можно запускать и тестировать. Все просто.
2.Программа растет. Вы делите ее на части и помещаете каждую в от% дельный файл, содержащий определенный функциональный блок. Сборка по%прежнему не вызывает затруднений. Теперь вы просто печатаете compiler main.c func1.c func2.c. Снова на выходе оказыва% ется исполняемая программа, которую вы тестируете, как и рань% ше. Никаких сверхусилий.
3.Вскоре у вас возникает понимание того, что некоторые части кода в действительности оказываются особыми компонентами с собст% венными проблемами – почти что самостоятельными библиотека% ми. С этими разделами кода проще работать, если поместить их в от% дельные каталоги, сгруппировав похожие секции кода. Вот теперь
1Очевидно, compiler нужно заменить той командой, которая запускает ваш
компилятор C; это лишь гипотетический пример.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
244m |
|||||
|
|
|
|
||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
. |
|
|
|
|
|
.c |
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
df |
|
|
n |
e |
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
Глава 10. Код, который построил ДжекClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
проект начинает разрастаться. Эту новую структуру кода можно со% брать, скомпилировав вручную каждый отдельный файл исходного кода и вызывая при этом компилятор таким образом, чтобы он не строил исполняемый модуль, а создавал промежуточные объектные файлы. После этого компилируется main.c и компонуется со всеми промежуточными объектными файлами. Для этого может также потребоваться задать компилятору включаемые файлы из некото% рых других каталогов. Задача становится несколько сложнее.
При каждом изменении кода в одном из новых каталогов вам при% дется запускать команду компиляции в этом каталоге, а потом еще раз выполнять окончательную команду «скомпоновать все». И все вручную. Кроме того, если вы измените заголовочный файл, ис% пользуемый другими каталогами, придется заново компилировать все те каталоги тоже. Если вы забудете это сделать, редактор свя% зей может выдать целый ряд непонятных сообщений об ошибках.
Чтобы избавиться от ввода многочисленных команд в командной строке, можно написать сценарий оболочки (или пакетный файл
в Windows), который обойдет все каталоги и в каждом запустит не% обходимые команды сборки. Когда исчезнут вся эта муторная рабо% та и скучный набор параметров компиляции, вы сможете снова за% няться серьезным делом – разработкой кода, и на душе у вас при этом будет покойно, потому что не нужно запоминать все это много% словие, требующееся для сборки.
4.В дальнейшем эти подкаталоги действительно становятся само% стоятельными библиотеками; они начинают использоваться в дру% гих проектах. Вы пригладите код, чтобы его использование стало немного удобнее, добавите рассчитанную на пользователя докумен% тацию, а затем измените команды сборки так, чтобы генерировать библиотеки общего доступа, а не объектные файлы. Для этого по% требуются дополнительные изменения в сценарии сборки, но они относительно невелики и не слишком обременительны.
5.Некоторое время разработка продолжается в том же духе. Объем кода быстро растет. Создаются многочисленные каталоги и подка% талоги. Несмотря на то что файловая структура выглядит довольно скромно, время, затрачиваемое на сборку, начинает вызывать про% блемы – когда вы запускаете сценарий сборки, заново компилиру% ются все исходные файлы, даже если в них нет никаких изменений. Возникает мысль о том, чтобы самостоятельно следить за всеми из% менениями и запускать сборку в подкаталогах тоже самостоятель% но (возможно, создавая для этого в каждом каталоге особые сцена% рии сборки). Но теперь проект вырос настолько, что легко пропус% тить какие%то зависимости. Это приведет к трудно разрешимым проблемам сборки или еще более тонким проблемам (например, не% которые ошибки не препятствуют выполнению сборки, но получае%
мая в результате программа ведет себя некорректно).
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Выполнениеm |
сборки |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
245Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Теперь дальнейшая разработка становится под угрозу срыва. Вы перестаете доверять системе, которая осуществляет сборку кода. Она ненадежна. Выполняемый модуль вызывает доверие лишь то% гда, когда каталоги полностью очищены от промежуточных моду% лей и сборка выполнена с чистого листа.
И тут появляется инструмент, который как раз предназначен для ра% боты в таких ситуациях. Классическим решением является програм% ма командной строки с оригинальным названием make (Feldman 78). Она вместо вас займется всеми промежуточными объектными файла% ми и правилами компиляции и, что главное, учтет зависимости между файлами. Эта программа получает указания в виде make%файлов, со% держащих необходимые правила сборки. Она смотрит на временны]е отметки исходных файлов и проверяет, какие из них изменились с мо% мента последнего запуска make, а потом перекомпилирует только их, а также те, которые от них зависят. Это более интеллектуальная вер% сия сценариев, которые мы писали раньше, специально ориентирован% ная на задачу компиляции и повторной компиляции программного обеспечения.
С течением лет появилось много разновидностей скромной программы make, часто оборудованных милым графическим интерфейсом. GNU Make – один из наиболее широко используемых инструментов (он бес% платный и отличается высокой гибкостью). Если вы пока не посвяще% ны в Культ make, то во врезке «Make: краткий обзор» на стр. 248 при% водится объяснение ее основных функций.
Существует множество других распространенных систем сборки, на% пример SCons, Ant, Nant и Jam. Все они ориентированы на конкрет% ную среду сборки (например, Nant применяется для сборки проектов
.NET) или на определенное свойство (многие пытаются упростить син% таксис make, который весьма вычурен!).
Выполнение сборки
Мы рассмотрели некоторые главные моменты построения сборки про% граммы в этом засасывающем болоте создания программного продук% та. В сущности, в любой процедуре сборки программы есть один или несколько файлов с исходным кодом на входе и некая выполняемая программа на выходе. Результатом может быть даже полный дистри% бутив программы, включая выполняемый файл, файлы подсказки, программу установки и т. д., которые будут тщательно упакованы и готовы к записи на CD.
Подобно той собирательной истории, у которой я беззастенчиво позаим% ствовал название данной главы, по мере развития и совершенствования нашего программного обеспечения развивается и совершенствуется процесс его сборки. Возможно, в вашем случае процесс сборки не был вначале таким элементарным, как в приведенном примере, но обычно
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
246m |
|||||
|
|
|
|
||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
. |
|
|
|
|
|
.c |
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
df |
|
|
n |
e |
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
Глава 10. Код, который построил ДжекClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
оснастка для сборки сначала проста и развивается параллельно с ко% дом, для которого она создана. В крупном проекте часто участвует вну% шительная процедура сборки, требующая (но не всегда имеющая) аде% кватной документации. Мы рассмотрели компиляцию единственного файла исходного кода – фундаментальную стадию процесса, а теперь на ее основе возведем целое здание дополнительных действий.
Процесс сборки не ограничивается компиляцией исходных файлов. В него может также входить подготовка текстовых регистрационных файлов по шаблонам, создание интернационализированных строк для интерфейса пользователя или преобразование графических файлов
Сроки и условия
Следующие термины составляют основу терминологии построе% ния программного продукта:
Исходный код
Исходный код (source code) физически содержится в файлах, которые вы пишете, и обычно составляется на языке высокого уровня. С помощью надлежащих средств эти языковые конст% рукции могут быть преобразованы в работающую программу.
Компиляция
Исходный код преобразуется в выполняемый модуль одним из двух способов. Первый состоит в компиляции его в выпол% няемую программу. Альтернативой является интерпрета# ция исходного кода в реальном времени – языковая среда вре% мени исполнения выполняет синтаксический анализ и испол% няет исходный код при запуске программы.
Сборка
Это не вполне точный термин, который часто используют как синоним компиляции. Компиляция составляет один из эта% пов построения программы, тогда как сборка описывает весь процесс полностью. Термин make тоже используется неодно% значным образом; более того, это также название распростра% ненного инструмента сборки программ.
Объектный код
Объектный код хранится в объектном файле. Это компили% рованный вариант файла исходного кода. Объектный код нельзя выполнить непосредственно; он зависит от других файлов кода (большинство программ состоит из нескольких исходных файлов). Объектный файл должен быть скомпоно# ван с другими объектами, и тогда он может образовать испол# няемый модуль.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Выполнениеm |
сборки |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
247Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Библиотека
Библиотека кода похожа на объектный файл; это собрание компилированного кода, но сама она не является програм% мой. В библиотеке хранится связанное собрание полезной функциональности, которую можно включить в любую про% грамму. Библиотеки бывают статическими и динамически# ми. Первые компонуются как объектные файлы, вторые ди% намически загружаются приложением во время выполнения.
Машинный код
На некоторых стадиях результатом компиляции становится машинный код, а не объектные файлы. В таком виде исход% ный код представляет собой точные команды процессора для программы. Машинный код преобразуется в реальные коман% ды ЦП с помощью ассемблера, почему его также называют
кодом ассемблера.
Некоторые библиотеки ОС низкого уровня и встроенные про% граммы написаны на языке ассемблера, но обычно мы работа% ем на языках высокого уровня, а ассемблер оставляем компи% лятору в качестве его внутреннего механизма.
Компоновка
Редактор связей (linker) соединяет один или несколько объект# ных файлов (а возможно, и библиотек) в конечный исполняе% мый модуль или частично скомпонованную библиотеку кода.
Выполняемый модуль
Результат компиляции или компоновки. Это самостоятель% ная программа, которую можно непосредственно выполнять на компьютере.
в особый формат. Практически все такие виды деятельности можно включить в систему сборки и выполнять при обычном ее осуществле% нии. Это предполагает, что все инструменты должны иметь возмож% ность выполняться в составе сценариев – запускаться некоторой дру% гой программой (например, make).
Необходимо рассматривать свою систему сборки не отдельно, а как часть всего дерева исходного кода. Make%файлы должны храниться в системе управления версиями, как и исходные коды, и составлять часть программы. Это важно – без них вы не сможете собрать прило% жение.
Считайте систему сборки частью дерева исходного кода и ведите их совме& стно. Они тесно связаны между собой.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
248m |
|||||
|
|
|
|
||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
. |
|
|
|
|
|
.c |
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
df |
|
|
n |
e |
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
Глава 10. Код, который построил ДжекClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Make: краткий обзор
Make – одна из наиболее широко применяемых систем сборки в мире программирования. Промчимся вихрем по ее организа% ции и возможностям.
Make управляется make#файлами, которые обычно располагают% ся в каталогах по соседству с исходным кодом, который они со% бирают. Эти make%файлы содержат правила, описывающие сбор% ку приложения. Каждое правило описывает цель (target, про% грамму или промежуточную библиотеку), детали, от которой она зависит, и как ее создавать. Комментариям в файле предше% ствует #. Вот короткий пример, в котором для сборки источника используется гипотетическая программа compiler:
#Первое правило утверждает: ".o!файлы можно собирать
#из .c!файлов, и вот команда для этого."
#$< и $@ ! это специальные символы для файлов источника
#и приемника. Да, синтаксис make бывает загадочным...
%.o: %.c
compiler object $@ $<
#Это правило говорит: "программа myapp собирается из трех файлов .o,
#и вот как компоновать их вместе"
myapp: main.o func1.o func2.o
linker output $@ main.o func1.o func2.o
Это общая идея. Если сохранить текст в файле с именем Makefile и выполнить команду make myapp, произойдет загрузка и синтак% сический анализ этого файла. Так как myapp зависит от несколь% ких .o%файлов, то сначала они будут собраны из соответствую% щих .c%файлов с помощью указанных правил. Затем будет вы% полнена команда редактора связей, которая создаст приложение.
Есть много способов приукрасить эту процедуру и сделать ее бо% лее управляемой. Например, в make%файлах можно определять переменные, и тогда правило myapp будет выглядеть изящнее:
OBJECT_FILES=main.o func1.o func2.o myapp: $(OBJECT_FILES)
linker output $@ $(OBJECT_FILES)
Подробное обсуждение всех деталей применения make выходит за рамки этой книги, но они должны быть известны каждому разработчику. Есть очень много полезных функций. Средства сборки с GUI фактически представляют собой оболочки над эти% ми функциями, скрывая детали составления make%файлов. Обычно они легче настраиваются, но могут препятствовать соз% данию особо сложных конфигураций сборки.