Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Гудлиф - Ремесло программиста.pdf
Скачиваний:
182
Добавлен:
16.05.2015
Размер:
9.67 Mб
Скачать

238

Глава 10. Код, который построил Джек

пропускать наш исходный код через компилятор (или интерпретатор), чтобы получить то, что работает так, как нам хотелось бы. Неизменно оно отказывается это делать. Смыть и повторить.

Задача, состоящая в том, чтобы преобразовать тщательно отшлифо% ванный код на языке высокого уровня в исполняемый модуль, кото% рый можно распространять среди пользователей, обычно называется сборкой кода (building code), хотя в большинстве случаев этот термин используют наравне с компиляцией (making, compiling).

Процедура сборки является базовой – нельзя разрабатывать код, не выполняя сборки. Поэтому важно понимать, что] в нее входит и как ра% ботает ваша система сборки – лишь тогда можно иметь хоть какое%то доверие к генерируемому коду. Здесь играет роль ряд довольно тонких факторов, особенно если базовый код достигает внушительных разме% ров. Любопытно, что почти все учебники программирования благопо% лучно пропускают эту тему; они ограничиваются примерами про% грамм, состоящих из единственного файла, что не отражает реальной сложности процедуры сборки.

Многие разработчики полагаются на систему сборки своей интегриро% ванной среды, но это не снимает с них обязанности разобраться, как она работает. Очень удобно, когда можно нажатием кнопки сгенерировать весь код, но если вы не знаете, какие опции передаются компилятору C или на каком уровне находятся вспомогательные средства, сохраняе% мые в объектных файлах, то вы слабо контролируете ситуацию. То же самое происходит, когда вы вводите в командной строке одну команду сборки. Вы должны понимать, какие скрытые действия производятся, и только тогда сможете многократно осуществлять надежную сборку.

Языковые барьеры

Есть несколько разновидностей языков программирования, в каждой из которых существует своя механическая процедура построения ис% полняемой программы из исходного кода. Модели построения разли% чаются по сложности, и у каждой есть свои сильные и слабые стороны.

Три основных механизма – это интерпретируемые языки, компили# руемые языки и языки, компилируемые в байт#коды. Они представле% ны на рис. 10.1.

Интерпретируемые языки

Коду, написанному на интерпретируемом языке, не требуется прохо% дить через особую фазу сборки. Написав некий код, нужно лишь сооб% щить интерпретатору, где он лежит; интерпретатор станет анализиро% вать код и выполнять инструкции в реальном времени. Распространен% ными интерпретируемыми языками являются Perl, Python и Java% Script. Большинство OO%языков является интерпретируемыми, в основ%

Языковые барьеры

239

 

 

 

 

 

1.

Интерпретируемые языки

 

 

 

 

 

2.

Компилируемые языки

 

 

Файлы

 

 

3.

Языки, компилируемые в байт7код

 

 

 

 

4.

Выполнение с JIT7компиляцией

 

1

с исходным

3

 

 

Применение

 

кодом

 

 

инструмента сборки

 

 

 

 

 

Интерпретатор

 

2

 

 

 

Байт7компилятор

 

 

 

 

 

 

 

Компилятор

 

 

 

 

 

Выполняемый модуль

4

Байт7код

Выполнение

JIT7компилятор

 

Интерпретатор

01010101

Выход

01010101

Рис. 10.1. Методы сборки и выполнения языков программирования

ном потому, что они разработаны не так давно – когда компьютеры смогли выполнять интерпретацию с разумной скоростью.

Главное достоинство интерпретируемых языков – скорость разработ% ки программ, обусловленная отсутствием промежуточной стадии ком# пиляции; все изменения можно очень быстро проверить. Кроме того, достигается независимость от платформы – интерпретаторы популяр% ных языков работают на многих платформах. Ваша программа сможет работать всюду, куда был перенесен интерпретатор.

Но у интерпретируемых программ есть недостатки: они выполняются медленнее, чем компилированные эквиваленты, поскольку на этапе ис% полнения нужно прочесть, проанализировать, интерпретировать и вы% полнить каждую отдельную команду кода. Это большая работа. Совре% менные машины настолько быстры, что проблемы интерпретации воз% никают только в приложениях, требующих особенно интенсивных вы% числений. Существуют также различные технологии интерпретации, увеличивающие производительность кода: в некоторых языках исход% ные тексты компилируются перед выполнением (что увеличивает вре% мя запуска программы) или применяют компиляцию Just#In#Time (JIT), когда каждая функция компилируется непосредственно перед ее исполнением (что замедляет первое обращение к каждой функции). Для большинства программ такие накладные расходы приемлемы, а работа в режиме JIT%компиляции неотличима от выполнения обыч% ного скомпилированного кода.

240

Глава 10. Код, который построил Джек

Действительно ли мы собираем программы?

«Сборка» часто используется в качестве метафоры программиро% вания, равносильной тому, что происходит в «нормальной» сбо% рочной промышленности. Между ними есть много глубоких па% раллелей, поскольку в том и другом случае мы имеем дело со строительными процессами. И мы действительно наблюдали в известной мере частичное совпадение и сотрудничество между двумя отраслями в виде движения «паттернов программирова% ния» (см. «Шаблоны проектирования» на стр. 334), примером чего служит книга Кристофера Александра (Christopher Alexan% der) об архитектуре (Alexander 79).

Важно понять пределы этой метафоры и ее реальную ценность. В конце концов, нет идеальных метафор. Хотя это абстрактный вопрос, лежащий несколько в стороне, он важен, поскольку срав% нение неизбежно вызовет предвзятость нашего подхода к разра% ботке. Метафора хороша к месту; в иных случаях она может быть неудачна и даже вредна.

Положительное

Как и в физическом процессе строительства здания, мы начи% наем с нуля и осуществляем строительство, помещая слои структуры один на другой. До начала строительства должны быть выполнены сбор технических требований и тщательное проектирование и разработка архитектуры. Можно особенно не заниматься планированием, если нужно построить садовую беседку, но было бы безумием рассчитывать на то, что без предварительного планирования может вырасти небоскреб; для его появления необходимы серьезные предварительные усилия по проектированию и планированию. Здесь параллель с созданием программного обеспечения достаточно близка.

Отрицательное

В остальных областях метафора оказывается довольно сла% бой. Например, базовые уровни программной конструкции модифицировать значительно легче, чем фундамент здания. Гораздо дешевле разрушить программное сооружение, чем физическое. Это говорит о том, что в области программирова% ния возможности создания прототипов и исследования шире, чем в физическом мире.

Строительство реальных сооружений основано на твердых инженерных принципах: они отражены в законодательных актах и предполагают легальную ответственность. Многие фирмы%производители программного обеспечения в глаза не видели никаких инженерных принципов.

Языковые барьеры

241

Самое страшное

В целом процедура разработки похожа на процесс физическо% го строительства, включая в себя замысел системы, проекти% рование, реализацию и пробную эксплуатацию. Но в данной главе мы озабочены несколько иным – компиляцией и проце% дурами, входящими в такого рода строительные задачи. Здесь метафора тоже оказывается не вполне удачной. Каж% дый раз, взяв новый экземпляр исходного кода, вы «строите» его, создавая выполняемую программу – об этом здесь и идет речь. Обратите внимание на два разных употребления терми% на «build» (сборка, строительство).

Процесс построения программного продукта подчинен своим правилам: если вы модифицируете функцию, то должны по% том заново построить систему. В противоположность этому, если вы покрасили двери, вам не нужно заново возводить сте% ны своего дома.

Языки сценариев часто являются интерпретируемыми. У этих языков очень быстрый цикл разработки благодаря терпимому отношению к сомнительному коду (в языке нет строгих правил и слабая типизация) и отсутствию сложных функций. Языки сценариев часто используют% ся в качестве связующей среды для более удобного вызова других ути% лит. Примерами языков сценариев служат сценарии оболочки UNIX, пакетные файлы Windows и Tcl.

Компилируемые языки

В компилируемых языках для преобразования файлов исходного кода

вмашинные инструкции на целевой платформе применяется после% довательность инструментов. Обычно целевая платформа совпадает с платформой разработки, однако разработчики встроенного ПО часто работают на ПК, а целевыми могут быть самые разные машины, для чего применяются кросс#компиляторы. Крупные проекты компилиру% ются поэтапно: отдельные файлы с исходным кодом компилируются

впромежуточные объектные файлы, а затем эти объекты компонуются

вокончательный исполняемый модуль. Эту модель иллюстрирует мета% фора выпекания пирога, показанная на рис. 10.2, где отдельные ингре% диенты (исходные файлы) перемешиваются (компилируются) и нако% нец запекаются все вместе (компонуются).

Из компилируемых языков наиболее популярны C и C++, хотя компи% лируется большинство структурированных языков. Совершенно естест% венно, что скомпилированное приложение будет выполняться быстрее, чем его интерпретируемый аналог (по крайней мере, в отсутствие JIT% компиляции), хотя на практике вы этого не заметите; большинство

242

Глава 10. Код, который построил Джек

Рис. 10.2. Кухня компиляции

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

Для компилируемых языков процедура сборки сложнее, чем при ин% терпретации, поэтому возможностей для возникновения сбоев в них больше. Для каждой платформы, на которой планируется выполнять приложение, оно должно быть скомпилировано отдельно.1

Языки, компилируемые в байтNкоды

Компилируемые в байт%коды языки занимают промежуточное поло% жение между интерпретируемыми и компилируемыми языками. Они предполагают этап компиляции, но не создают обычной исполняемой программы. Результатом является файл, содержащий байт#коды: псевдомашинный язык, который может выполняться на виртуальной машине. Примером таких языков служат Java и C#.

1Целевые платформы различаются по типам процессоров и операционных систем. Могут иметь значение и другие факторы, такие как имеющееся пе% риферийное оборудование.