Вы, наверное удивитесь, но чтобы написать учебник, надо знать системы сборки из софтверного БигТеха и, как ни странно, старый добрый сишный препроцессор (cpp). Да, господа… Именно так… Сейчас объясню, почему…
В front-end разработке существует язык разметки LaTeХ. Многие про него слышали и некоторые его используют. Это язык создан для вёрстки прекрасно скомпонованных документов. Например все datasheet(ы) на культовые мировые микроконтроллеры по 5000+ страниц как раз собраны именно через утилиту LaTeX. Обычно на LaTeX профессионально работают так называемые технические писатели. В западной академической среде тоже активно применяют LaTeX для вёрстки своих публикаций на IEEE Explore и для подготовки слайдов на всяческие околонаучные конференции.
При оформлении книги в latex автор не должен думать об оформлении. Автор думает о содержании. За оформление автор ответственности не несёт. Вся ответственность за оформление страниц перекладывается на компилятор LaTeX. В этом основная концепция.
Ещё достоинство LaTeX в том, что для того, чтобы создать *.pdf документ с нужными отступами, нумерацией, картинками, 7-ми этажными формулами, уравнениями и прочей прекрасной полиграфией вам абсолютно не нужна компьютерная мышка. Да… Вот так…
В этой заметке я покажу несколько трюков по работе с LaTeX.
Итак, танцуем от печки…
Что надо из софтвера (ПО)?
№ |
Название утилиты |
CygWin |
Пояснение |
1 |
cpp |
+ |
Препроцессор языка Си |
2 |
pdf viewer |
|
Обозреватель pdf файлов |
3 |
pandoc |
|
утилита для преобразования latex в docx |
4 |
cmd |
|
Интерпретатор языка Batch |
5 |
make |
+ |
Интерпретатор языка make |
6 |
pdflatex |
|
Интерпретатор языка LaTeX |
7 |
Eclipse IDE |
|
Текстовый редактор Eclipse |
8 |
git |
+ |
Система контроля версий для ваших текстов учебника |
12 |
realpath |
+ |
Вычислить абсолютный путь к папке |
13 |
sort |
+ |
Утилита для сортировки строк. Например для списка акронимов. |
9 |
tree |
+ |
Обозреватель содержимого папки |
10 |
m4 |
+ |
Универсальный препроцессор. Целый скриптовый язык. |
11 |
grep |
+ |
Поиск по ключевому слову на жестком диске |
Большинство этих утилит преспокойно берутся из CygWin или MinGW.
Каков план?
Я предлагаю построить и пустить вот такой конвейер метаморфоза файликов.
Зелёным цветом покрашены те файлы, которые являются для нас исходниками. Это то самое, что надо подвергать версионному контролю в git репозитории. GNU Make тут выступает дирижером оркестра и механической коробкой передач одновременно.
На каждую главу книги создается *.texi файл, *.mk файл и папка с картинками. Вот пример *.texi файла для главы:
sinclude(`latex_m4_preproc_utils.texi') \graphicspath{ {PATH_CHAPTER_X_DIR/pix} } \chapter{Название Главы} \section{Пролог} ххххххххххххх \section{Параграф\_1} хххххххххх \section{Итог} хххххххххххх \section{Гиперссылки} \begin{enumerate} \item \href{wwwwwwwwwwwwwwwww}{zzzzzzzzzzzz} \end{enumerate}
На вход препроцессора cpp(или m4) подаются файлы *.texi. На утилиту pdflatex мы подаем выход самого обыкновенного сишного препроцессора (консольная утилита cpp) — то есть файл *.tex.
Если проводить аналогию, то LaTex — это как компоновщик LD из разработки ПО, только не для бинарного кода, а для обыкновенного человекочитаемого текста. Вот такие вот пирожки с капустой.
Допустим, вы пишете курсовой проект, магистерский диплом, datasheet на навороченный ASIC с 270-ю SPI-регистрами или учебник по программированию. Что надо уметь делать на Latex? На самом деле достаточно много всего разного. Однако вот минимальный джентльменский набор:
-
Вставка изображения
-
Вставка цитаты
-
Вставка кусков кода (так называемые листинги)
-
Вставка таблицы
-
Вставка перечислений
-
Вставка гиперссылок
-
Вставка уравнений
-
Вставка оглавления
-
Вставка списка литературы
А теперь обо всем по порядку.
Вставка изображения
Этот кусок LaTeX-кода производит вставку изображения с именем arch.png
\begin{figure}[h] \centering \includegraphics[width=0.99\textwidth]{arch} \caption{Harvard architecture } \label{fig:mesh1} \end{figure}
Можно даже создать макрофункцию для вставки картинки одной строчкой. Вот так: INSERT_PIX( arch , Harvard architecture ). LaTeX сам найдет подходящий по контексту файл изображения в проиндексированных путях.
#define INSERT_PIX(FILE_NAME,HINT ) \ \begin{figure}[h] \ \centering \ \includegraphics[width=0.99\textwidth]{FILE_NAME} \ \caption{HINT } \ \label{fig:FILE_NAME} \ \end{figure}
Как на Latex оформить цитату?
В любом тексте от случая к случаю приходится вставлять цитаты. На LaTeX это можно сделать так:
\begin{quote} В любом деле важно определить приоритеты. Иначе второстепенное, хотя и нужное, отнимет все силы и не даст дойти до главного. \end{quote}
Как оформить вставку куска с кодом?
Вставка листинга с исходным кодом:
\begin{lstlisting}[label=some-code,caption=Правильный if] int ret = NVRAM_Get(ID_IPv4_ROLE, tmp, 1, &tmp_len); if (MM_RET_CODE_OK != ret) { return ERROR_CODE_HARDWARE_FAULT; } \end{lstlisting}
Если вы пишете учебник по Си и вставляете листинги с Си-кодом в LaTex код, то препроцессор будет пытаться вставить include-ы, которых на самом деле нет, и выдаст ошибку. Всё заклинит. Поэтому придется убирать символ # из листингов с кодом и писать справку (*), что надо подразумевать первым символом в строке символ #.
Как оформить таблицу?
Таблицы постоянно встречаются в текстах. Вот так они пишутся на LaTeX:
\begin{tabular} {ll} Акроним & Расшифровка \\ \hline TUI & Text-based user interface \\ CLI & command-line interface \\ UART & universal asynchronous receiver / transmitter \\ JTAG & Joint Test Action Group \\ LED & light-emitting diode \\ CIC & Cascaded integrator–comb \\ \end{tabular}
Как оформить перечисление «чиво-либо»?
В любых текстах то там то здесь постоянно появляются списки всяческих пунктиков. В LaTex это оформляется так:
\begin{enumerate} \item One \item Two \item Three \end{enumerate}
Как оформить гиперссылки?
В гиперссылки можно заточить список литераторы:
\section{Гиперссылки} \begin{enumerate} \item \href{https://habr.com/ru/post/673522/}{Настройка ToolChain(а) для Win10+GCC+С+Makefile+ARM Cortex-Mx+GDB} \item \href{https://habr.com/ru/post/111691/}{Пример Makefile} \item \href{https://www.opennet.ru/docs/RUS/gnumake/}{Эффективное использование GNU Make} \item \href{https://habr.com/ru/articles/857416}{Обновление Прошивки из Make Скрипта} \item \href{https://www.youtube.com/watch?v=HEEVxZ4rBCo}{CI/CD прошивок для микроконтроллеров в Wiren Board ( начало на 25:20)} \item \href{https://www.youtube.com/watch?v=vmuO4bHjTSo&t=7s}{Конвеерум 30: Эволюция рабочего окружения для embedded разработки} \item \href{https://habr.com/ru/post/47513/}{GNU Make может больше чем ты думаешь} \end{enumerate}
Как настроить препроцессор CPP?
Как многим известно, Си-препроцессор можно преспокойно использовать для любого другого языка программирования (не только Си) или любого другого текста в общем. Разработчики препроцессора даже добавили специальные ключи для этого. Вот такой пучок опций надо подать на утилиту cpp для активации универсального препроцессора:
Опция (ключ CLI) |
Пояснение |
Пояснение |
-E |
textual output from the preprocessor will be in UTF-8. |
Заставить препроцессор сохранять в кодировке UTF-8 |
-P |
Inhibit generation of linemarkers |
Убрать лишние комментарии на выходе препроцессора. Эта опция специально для не Си кода |
-C |
Do not discard comments |
Не отбрасывать комментарии |
-traditional-cpp |
Traditional Mode |
Не удалять на выходе последовательно идущие пробелы |
-nostdinc |
Do not search the standard system directories for header files |
Не искать заголовочные файлы в стандартных директориях |
-fexec-charset=UTF-8 |
Set the execution character set |
Задать кодирование символов в кодировке UTF-8 |
-DHAS_XXX |
|
Передать макрос HAS_XXX через командную строку |
-undef |
Do not predefine any system-specific or GCC-specific macros. The standard |
Не использовать макросы от компилятора Си кода. Они тут не нужны, так как нет самого исполняемого кода. |
Препроцессором cpp можно не только собирать Си-код, но также и верстать LaTeX, компоновать графы в GraphViz, перекраивать Assembler код, перетасовывать LD скрипты компоновщика и всё, на что только вам хватит фантазии. Сишный препроцессор — это дубовая вещь.
Структура репозитория
Вот так может выглядеть папка с исходниками учебника. На каждую главу по отдельной папочке.
> C:\cygwin64\bin\tree.exe . ├── about_author │ ├── about_author.mk │ ├── about_author.texi │ └── pix ├── attributes_of_good_firmware │ ├── attributes_of_good_firmware.mk │ ├── attributes_of_good_firmware.texi │ └── pix │ ├── free.png │ ├── nano.png │ └── ubolx_od.png ├── bibliography │ ├── bibliography.mk │ ├── bibliography.texi │ └── pix ├── good_swc │ ├── good_swc.mk │ ├── good_swc.texi │ └── pix │ ├── arch.png │ ├── folder.png │ ├── list.png │ ├── reg.png │ └── scan.png ├── latex_misc.texi ├── library.mk ├── preamble.texi └── why_make ├── pix │ ├── IAR.png │ ├── diff.png │ ├── pc.png │ ├── perf.png │ ├── reactor.png │ └── spher.png ├── why_make.mk └── why_make.texi 12 directories, 33 files >
Корневой Latex файл
А это, господа, корневой LaTeX файл, в который, в зависимости от конфига, препроцессор и вмонтирует все кусочки глав.
\documentclass[a4paper, 16pt]{book} #include "preamble.texi" \begin{document} \title{ \textbf{ Название брошюры }} \author{aabzel} \date{\today} \maketitle \tableofcontents #ifdef HAS_ABOUT_AUTHOR #include "about_author.texi" #endif #ifdef HAS_ATTRIBUTES_OF_GOOD_FIRMWARE #include "attributes_of_good_firmware.texi" #endif #ifdef HAS_GOOD_SWC #include "good_swc.texi" #endif #ifdef HAS_WHY_MAKE #include "why_make.texi" #endif #ifdef HAS_BIBLIOGRAPHY #include "bibliography.texi" #endif \end{document}
преамбула preamble.texi у меня вот такая
\usepackage[T2A]{fontenc} \usepackage{cmap} % для копипасты из PDF \usepackage{uarial} \renewcommand{\familydefault}{\sfdefault} \usepackage{hyperref} \usepackage{graphicx} \usepackage[utf8]{inputenc} \usepackage[russian]{babel} \usepackage{listings} \usepackage{listingsutf8} \usepackage[margin=0.6in]{geometry} \usepackage{indentfirst} % для русских красных строк \geometry{top=20mm} \setlength{\parindent}{1.25cm} \sffamily \usepackage[fontsize=14.0pt]{fontsize} \renewcommand{\sfdefault}{cmss}
Специально вынес преамбулу в отдельный *.texi файл, чтобы без причины не мозолить глаза.
Отдельный же *.texi файл для главы выглядит вот так:
\graphicspath{ {PATH_CHAPTER_X_DIR/pix} } \chapter{Название главы} Текст главы
Тут можно заметить, что препроцессор вставит переменную PATH_CHAPTER_X_DIR, которая укажет абсолютный путь к этой папке. Сам путь расcчитает make скрипт. Поэтому куда бы вы ни клонировали из GIT исходники LaTeX, путь к картинкам встанет в нужное значение автоматически. Вы уже любите препроцессор?
Скрипты MAKE файлов
Это корневой файл
ARTIFACT_NAME=main_generated FINAL_LATEX_FILE =$(ARTIFACT_NAME).tex ARTIFACT_DOCS=$(ARTIFACT_NAME).docx ARTIFACT_PDF=$(ARTIFACT_NAME).pdf BUILD_DIR=artifacts CPP_OPT += -undef CPP_OPT += -E CPP_OPT += -P CPP_OPT += -C CPP_OPT += -fexec-charset=UTF-8 CPP_OPT += -traditional-cpp CPP_OPT += -nostdinc CPP_OPT += $(OPT) PANDOC_OPT += -f latex PANDOC_OPT += -t docx $(ARTIFACT_DOCS) : $(FINAL_LATEX_FILE) pandoc -s $^ $(PANDOC_OPT) -o $@ $(FINAL_LATEX_FILE):$(SOURCES_DOT) $(BUILD_DIR) $(info Preproc...) cpp main.texi $(CPP_OPT) $(INCDIR) -E -o $@ $(ARTIFACT_PDF): $(FINAL_LATEX_FILE) $(BUILD_DIR) $(info generate_pdf...) ./latex.bat $(FINAL_LATEX_FILE) move_artifacts: $(BUILD_DIR) mv $(ARTIFACT_DOCS) $(BUILD_DIR)/$(ARTIFACT_DOCS) mv $(ARTIFACT_PDF) $(BUILD_DIR)/$(ARTIFACT_PDF) all: $(ARTIFACT_PDF) $(ARTIFACT_DOCS) move_artifacts $(info All) $(BUILD_DIR): mkdir -p $@ clean: $(info clean) rm $(ART_PDV) rm $(FINAL_LATEX_FILE) -rm -fR $(BUILD_DIR) include $(DOCUMENTATION_DIR)/library/library.mk
Это файл library.mk
$(info LIBRARY_MK_INC=$(LIBRARY_MK_INC) ) ifneq ($(LIBRARY_MK_INC),Y) LIBRARY_MK_INC=Y LIBRARY_DIR=$(DOCUMENTATION_DIR)/library INCDIR += -I$(LIBRARY_DIR) OPT += -DHAS_LIBRARY ifeq ($(ABOUT_AUTHOR),Y) include $(LIBRARY_DIR)/about_author/about_author.mk endif ifeq ($(CHAPTER_1),Y) include $(LIBRARY_DIR)/chapter_1/chapter_1.mk endif ifeq ($(CHAPTER_2),Y) include $(LIBRARY_DIR)/chapter_2/chapter_2.mk endif ifeq ($(CHAPTER_3),Y) include $(LIBRARY_DIR)/chapter_3/chapter_3.mk endif ifeq ($(BIBLIOGRAPHY),Y) include $(LIBRARY_DIR)/bibliography/bibliography.mk endif endif
Ну и make-файл для главы. Тут вместо CHAPTER_X и chapter_x вы просто подставите название своей главы.
$(info CHAPTER_X_MK_INC=$(CHAPTER_X_MK_INC) ) ifneq ($(CHAPTER_X_MK_INC),Y) CHAPTER_X_MK_INC=Y CHAPTER_X_DIR=$(LIBRARY_DIR)/chapter_x #@echo $(error CHAPTER_X_DIR=$(CHAPTER_X_DIR)) INCDIR += -I$(CHAPTER_X_DIR) OPT += -DHAS_CHAPTER_X_DIR OPT += -DHAS_FOREIGN_AUTHORS OPT += -DPATH_CHAPTER_X_DIR=$(CHAPTER_X_DIR) endif
В файле config.mk вы просто декларативно выбираете, какие главы вставлять в вашу книгу, а какие выпиливать:
ABOUT_AUTHOR=Y CHAPTER_1=N CHAPTER_2=Y CHAPTER_3=N BIBLIOGRAPHY=Y
И, наконец, сам Makefile. Как можно заметить, в языке make тоже есть свой препроцессор — команда include
PROJECT_PATH:=$(dir $(realpath $(lastword $(MAKEFILE_LIST)))) DOCUMENTATION_DIR:=$(PROJECT_PATH)../../../docs PROJECT_PATH:=$(subst /cygdrive/c/,C:/,$(PROJECT_PATH)) DOCUMENTATION_DIR:=$(subst /cygdrive/c/,C:/,$(DOCUMENTATION_DIR)) INCDIR += -I$(PROJECT_PATH) INCDIR += -I$(WORKSPACE_LOC) include $(PROJECT_PATH)config.mk include $(DOCUMENTATION_DIR)/docs.mk include $(DOCUMENTATION_DIR)/make_scripts/typeset_book.mk
Теперь только остается дзыкнуть по *.bat-скрипту, который выполнит в консоли make -i all и у вас в этой папке появится *.docx и готовый для печати *.pdf файл. Easy!
Демо-версию получившегося учебника можно посмотреть тут
Важные моменты
1—Все latex исходники должны быть в формате кодирования UTF-8. Иначе утилита pandoc вам сгенерирует *.docs с кракозябрами.
Сборка учебника на CI сервере Jenkins
А теперь приятный бонус. Этот make скрипт сборки учебника, который мы написали скармливаем серверу сборки Jenkins и сервер сам нам теперь будет собирать *.pdf(ку) после каждого коммита в репозиторий. Автоматически. Здорово! Вы уже любите скрипты cборки?
Плюс в том, что сервер сборки даст вам гарантию, что вы ничего не забыли загрузить в git репозиторий.
Достоинства тандема LaTex + препроцессора
++ Вы получаете полностью конфигурируемый процесс сборки своей брошюры. Благодаря системе сборки Вы можете автоматически синтезировать множество вариаций одного и того же учебника, меняя набор глав и содержание, просто манипулируя переменными окружения в скриптах сборки make. Вам уже нравится сиcтема сборки GNU Make?…
++ Вы получаете полностью бесплатный инструментарий для вёрстки своего дока. Все консольные утилиты свободно скачиваются.
++ Благодаря скриптам Вы можете верстать учебник автоматически на серверах сборки рядом с прошивками. Всё, что от вас требуется это сделать комит в git и, вуаля, у вас новое издание книги.
Недостатки CPP
— Если вы пишете учебник по Си и вставляете листинги с Си-кодом в LaTex код, то препроцессор будет пытаться вставить include-ы, которых на самом деле нет, и выдаст ошибку. Всё заклинит. Поэтому придется убирать символ # из листингов с кодом и писать справку, что надо подразумевать тут символ #.
Однако это легко решается. Существует ещё более универсальный препроцессор c лаконичным названием: m4. Надо просто реинкарнировать препроцессор m4 из 197x. Тут он даже более применим нежели cpp.
Как мигрировать с препроцессора CPP на препроцессор M4?
Так происходит условная вставка содержимого заголовочного файла:
----------------------------- CPP #define HAS_FILE1 #ifdef HAS_FILE1 #include "file1.txt" #endif ---------------------------- M4 define(HAS_FILE2) ifdef(`HAS_FILE1', `include(`file1.txt')', ) -------------------------------
Так происходит макро-подстановка с заменой:
--------------------------------------------- CPP #define INSERT_PIX(FILE_NAME,HINT, TOKEN ) \ \begin{figure}[h] \ \centering \ \includegraphics[width=0.99\textwidth]{FILE_NAME} \ \caption{HINT } \ \label{fig:TOKEN} \ \end{figure} INSERT_PIX(IL_62.jpg, IL-62 cocpit, IL_62) INSERT_PIX(cat.jpg, Изображение кота, cat) ------------------------------------ M4 define(INSERT_PIX, format( \begin{figure}[h] \centering \includegraphics[width=0.99\textwidth]{%s} \caption{%s } \label{fig:%s} \end{figure} , $1, $2 , $3 ) ) INSERT_PIX(IL_62.jpg, IL-62 cocpit, IL_62) INSERT_PIX(cat.jpg, Изображение кота, cat)
Условная вставка кода:
---------------------------------------------------------- CPP #ifdef HAS_FOREIGN_AUTHORS \item Цифровая обработка сигналов, Стивен Смит,2018 \item Extreme C, Kamran Amini, 2019 \item Язык С в XXI веке, Бен Клеменс , 2015 \item Алгоритмические трюки для программистов, Генри Уоррен-мл., 2014 \item Архитектура встраиваемых систем, Даниэле Лакамера, 2023 #endif ------------------------------------------------------------------- M4 ifdef(`HAS_FOREIGN_AUTHORS', ` \item Цифровая обработка сигналов, Стивен Смит,2018 \item Extreme C, Kamran Amini, 2019 \item Язык С в XXI веке, Бен Клеменс , 2015 \item Алгоритмические трюки для программистов, Генри Уоррен-мл., 2014 \item Архитектура встраиваемых систем, Даниэле Лакамера, 2023 ' ) -------------------------------------------------------------------------------------------------------------------
Как сами видите, препроцессор M4 может всё тоже, что и препроцессор CPP, притом даже больше! M4 — это полноценный интерпретируемый язык программирования типа awk или python. Препроцессор M4 можно использовать даже как калькулятор формул.
Итоги
Удалось научиться верстать высокодобротную документацию кодом на LaTeX. Оказывается написание учебника, в общем-то, ничем не отличается от классической сборки компьютерных программ.
Вероятно такой тандемный способ верстки окажется по нутру как раз тем, кто пришел к разработке документации из какого-то программирования. Со своими погремушками.
Этот текст поможет вузовцам варить свои курсовые, дипломные работы, презентации и всяческие тезисы. Также этот текст поможет техническим писателям, программистам оформлять приятный doc food.
Вот так, господа. Теперь и Вы умеете верстать учебники и можете спокойно учить этому других.
Словарь
Акроним |
Расшифровка |
CPP |
C PreProcessor |
|
Portable Document Format |
UTF |
Unicode Transformation Format |
CLI |
Command-line interface |
GNU |
GNU’s Not UNIX |
UNIX |
Uniplexed Information and Computing System |
Ссылки
# |
Название источника |
1 |
Using the GNU Compiler Collection, Richard M. Stallman |
4 |
|
6 |
|
5 |
|
2 |
|
3 |
|
7 |
|
8 |
Вопросы:
-
Есть ли способ пометить участок кода так, чтобы Си препроцессор его не менял? Чтобы как встретилась строка #include «file.h» так и осталась в первозданном виде. (Спойлер: Никак, надо переходить на препроцессор M4)
-
Как сишным препроцессрором cpp вставить кусок текста макро функцией, сохранив при этом переносы строк? (Спойлер: Никак, надо переходить на препроцессор M4)
-
Существует ли аналог консольной утилиты clang-format только для LaTeX кода?
-
Как сделать так, чтобы LaTeX проверял русскую грамотность?
ссылка на оригинал статьи https://habr.com/ru/articles/859120/
Добавить комментарий