От переводчика
Продолжение Части 0,5
Как выясняется, C++ — язык довольно сложный для компиляции; да что там — он сложный даже для понимания. Я помню одну беседу о том, какими запутанными могут быть указатели на члены класса. Итоги были потрясающими и сводились к тому, что указатели могут указывать на члены, определенные в виртуальном базовом классе. В этом весь C++: отдельные вещи кажутся простыми, но как только вы начинаете их комбинировать с другими — дело сразу усложняется.
В это время мы были заняты добавлением новых возможностей в наш отладчик. Как выяснилось, создание «Вычислителя выражений» для C++ было так же вполне себе подвигом. «Вычислители» — звери довольно приятные. Они используются для вычисления значений выражений, которые в фактическом контексте компиляции были бы выражениями неверными (например, вычисление значения статической переменной вне текущей области видимости, или вычисление значение глобальной переменной из другого модуля). «Вычислитель» должен был выполнять все эти задачи, попутно будучи похожим по духу на исходный язык и максимально отзывчивым.
Я уже упоминал, что это все могло работать медленно?
В то время я работал над средой разработки для платформы Windows 3.0 — очередного так и не выпущенного проекта — и у нас были проблемы, связанные с попытками заставить
windows.h
компилироваться в сколько бы то ни было приемлемый отрезок времени.И именно тогда произошло чудо с предкомпилированными заголовочными файлами.
Я называю это «чудом» потому, что
.pch
буквально революционизировало наши подходы к созданию программных средств. Другие системы в прошлом использовали подобный подход, но наша была умнее. К примеру, из-за того, что наша система основывалась на образах скомпилированных заголовочных файлов, она гарантировала, что общий эффект заголовочных файлов в точке предкомпиляции был абсолютно идентичным в каждой единице компиляции. Это значило, что можно было разделять между модулями как информацию для отладки и навигации, так и внутреннее состояние компилятора. Тот факт, что после включения (#include
) заголовочного файла вы в двух единицах компиляции могли получить разные результаты, был проклятием разработчиков. И предкомпилированные заголовки нас спасли.Опять же: я не называю имен, но достаточно будет сказать, что я очень хорошо знаю того человека, который все это создал и что это было в стиле «да это невозможно», «даже не пытайся», «о, да у тебя получилось!».
В это же время еще одна команда работала над продуктом под названием Quick C for Windows, оказавшимся впоследствии невероятно важным. В этот продукт было вложено много труда; он имел первую настоящую IDE для Windows и настоящую отладку. Однако же все это было недоработано, и чуть позже я скажу, почему доведение всего этого до ума было делом непростым.
Пока суд да дело, та другая компания тоже не стояла на месте, а выпускала классные компиляторы C++. До 1992 года нам было нечем ответить: мы выпустили Microsoft C 7.0 на базе PBW и — буквально в тот же момент — Quick C for Windows (QCW).
Мой проект был закрыт. Да, опять. К счастью, я много где успел отметиться.
К слову сказать, Microsoft C 7.0 был, я думаю, самым тяжелым (именно с точки зрения массы) продуктом из когда-либо нами выпущенных. Я не уверен, что мы когда-то еще пытались выкатить так много книг.
Так вот мы выпустили эту книжную полку, а обстановка тем временем стала довольно интересной.
Еще раз выпустить PBW мы не могли; нам нужна была графическая среда разработки, базой для которой должен был стать QCW и уже шла работа по его обобщению и приспособлению под наши задачи, но работы там было — мама не горюй. К тому же, в нашей реализации C++ отсутствовали некоторые важные возможности; с Microsoft C 7.0 поставлялась очень ограниченная библиотека MFC 1.0. Нам нужно было что-то с этим предпринять. И увеличить скорость тоже не мешало бы.
Каждая из этих задач была пугающей, но я расскажу только о некоторых. Во-первых, отладка.
Отладка в 16-битной Windows (к тому времени, как мы закончили, на дворе уже была Windows 3.1) была волшебством. В Win16 была кооперативная многозадачность и не было «потоков» как таковых: был единственный поток выполнения. А теперь представьте себе, что это значило: процесс нельзя было остановить в принципе. Остановите процесс — и встанет вообще все. Так что если вы пытаетесь добиться того, чтобы GUI-отладчик останавливал отлаживаемую программу, то делать этого не стоило. Вместо того вам надо было сделать так, чтобы все выглядело так, будто программа остановилась, но на деле она продолжала бы работать, но исполнять она должна была не пользовательский код, а безобидный код, предоставленный отладчиком, который продолжал бы обрабатывать оконные сообщения.
Частью этого волшебства было то, что когда отлаживаемый процесс «останавливается», необходимо было «на лету» сабклассить все окна процесса и заменять
WndProc
на реализацию, отображающую белый прямоугольник вместо полноценной отрисовки, сохраняющую важные сообщения в очереди для последующей обработки и вообще выполняющую некую обработку «по умолчанию» с надеждой, что ничего плохого она не сделает. Фокус становился еще интересней, когда приложение пыталось отправить DDE- или OLE-сообщения. Это и было «чудо» Soft Mode отладки.Ах да, средства разработки… Была такая штука под названием Windows NT — вы, возможно, о ней слышали. И мы не хотели городить бинарники для различных окружений, так что надо было исправить подсистему «расширения DOS» с тем, чтобы можно было исполнять консольные приложения Windows NT в DOS. Впечатляюще. И все это должно было быть старым добрым DOS’ом. Дважды впечатляюще. Но мы это сделали (не без помощи третьей стороны, которую я называть не буду).
И да, средства разработки были медленными. Мы поднатужились и запихнули информацию для CodeView в
.pdb
-файлы для того, чтобы облегчить ту потерю информации, которую «обеспечивал» cvpack
. Это, несколько других изменений, — и впервые за довольно долгое время у нас появился самый быстрый компилятор C++ на рынке (по крайней мере, по данным нашей внутренней лаборатории; ваши ощущения могут отличаться).Пока мы занимались компилятором, дела MFC шли вполне себе хорошо. Там появился дизайнер, пара важных мастеров и все хозяйство начало выглядеть как VB: нарисовал, щелкнул, перетащил — готово!
Я обязан сказать пару слов о VB.
Кодовое имя Visual Basic 1.0 было Thunder (гром). Когда я впервые его услышал, оно показалось мне несколько самонадеянным. Я думал, что их поведение в стиле «Почувствуй силу грома!» было просто заносчивым хвастовством мальчишек. И я ошибался.
На то, что все продукты хотели быть похожими на Visual Basic и меняли название на Visual что-то-там, была своя причина. Visual Basic просто был очень хорош. Редко у кого был интерпретатор, обеспечивающий обратную связь «на лету», но воссоздать ключевые элементы Visual Basic’а стремился каждый. К тому времени, как мы закончили, Visual Basic был уже везде, и он глубоко повлиял на дизайн и библиотеки. У нас получился не Visual Basic, но что-то Visual: то был Visual C++ (если вы еще следите: Microsoft C 8.0 и MFC 2.0).
За этим последовал довольно интересный релиз, в котором мы заставили наши 16-битные средства работать под Windows NT в 16-битном же режиме (снимаем шляпу перед парнями из отдела совместимости приложений: нас не так просто было портировать), добавили поддержку OLE и ODBC. Клиентам это все очень нравилось и впервые за все время работы в Microsoft я ясно почувствовал, что у нас появилось преимущество над конкурентами в сфере средств разработки для C/C++. Язык был еще не полон, но то, что было — было действительно крутым.
Пока происходили эти события, часть нашей команды работала над очередной «действительно крутой» вещью: они портировали всё наше хозяйство под 32-битную Windows NT. Планировалось, что релиз состоится к моменту выхода Windows NT 3.5. Это, выпуск локализованной для Японии версии, а так же в принципе поддержка интернационализации, была важной, но абсолютно недооцененной работой.
Так появился Visual C++ 1.1.
Некоторые не совсем сознательные личности полагают, что версия 1.1 не была полноценным продуктом, а была «просто портированным продуктом». Это люди, очевидно, ничего не понимающие в средствах разработки. В системе версии 1.1 был абсолютно новый, 32-х битный, бэкенд компилятора. Мы все знаем, насколько портабельны эти бэкенды. И да, там был абсолютно новый отладчик с совершенно иным механизмом работы: в Windows NT таки были настоящие потоки, которые можно было останавливать. И опять же: модель памяти для всей программы была иной, поскольку исчезли ближние и дальние (
far
и near
) указатели. А так да, чо там, это все была мелочевка, а версия 1.1 был просто портом.Это было в 1993 году, продукт назывался Barracuda. Лично я там почти не отметился, но основные разработчики заслуживают отдельного упоминания в Истории.
Ситуация обещала стать очень интересной; важнейшим релизом набора средств для C++ на моей памяти был Visual C++ 1.0 “Caviar”. Не будь его — не было бы ничего. Но настолько же важным был и следующий релиз, о котором я напишу в следующий раз. Visual C++ 2.0 “Dolphin” впервые и на самом деле интегрировал средства разработки в один программный продукт.