Вы, наверное удивитесь, но чтобы написать учебник, надо знать системы сборки из софтверного БигТеха и, как ни странно, старый добрый сишный препроцессор (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 |
+ |
Система контроля версий для ваших текстов учебника |
9 |
tree |
+ |
Обозреватель содержимого папки |
10 |
m4 |
+ |
Универсальный препроцессор. Целый скриптовый язык. |
11 |
grep |
+ |
Поиск по ключевому слову на жестком диске |
Большинство этих утилит берутся из CygWin или MinGW.
Каков план?
Я предлагаю построить и пустить вот такой конвейер метаморфоза файликов.
Зелёным цветом покрашены те файлы, которые являются для нас исходниками. Это то самое, что надо подвергать версионному контролю в git репозитории. GNU Make тут выступает дирижером оркестра и механической коробкой передач одновременно.
На каждую главу книги создается *.texi файл, *.mk файл и папка с картинками. На вход препроцессора cpp подаются файлы *.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=Битовое поле для регистра]
/* page 105 7.2.27 Register file: 0x19 – DW1000 State Information*/
typedef union {
uint8_t byte[4];
uint32_t dword;
struct {
uint32_t tx_state : 4; /*bit 0-3: TX_STATE*/
uint32_t res1 : 4; /*bit 4-7: */
uint32_t rx_state: 5; /*bit 8-12: RX_STATE*/
uint32_t res2 : 3; /*bit 13-15:*/
uint32_t pmsc_state : 4; /*bit 16-19: PMSC_STATE*/
uint32_t res3 : 12; /*bit 20-31:*/
};
} Dwm1000SysState_t;
\end{lstlisting}
Если вы пишете учебник по Си и вставляете листинги с Си-кодом в LaTex код, то препроцессор будет пытаться вставить include-ы, которых на самом деле нет, и выдаст ошибку. Всё заклинит. Поэтому придется убирать символ # из листингов с кодом и писать справку (*), что надо подразумевать первым символом в строке символ #.
Как оформить гиперссылки?
\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
Теперь только остается набрать в консоли make all и у вас в этой папке появится *.docx и готовый для печати *.pdf файл. Easy!
Демо-версию получившегося учебника можно посмотреть тут
Важные моменты
1--Все latex исходники должны быть в формате кодирования UTF-8. Иначе утилита pandoc вам сгенерирует *.docs с кракозябрами.
Сборка учебника на CI сервере Jenkins
А теперь приятный бонус. Этот make скрипт сборки учебника, который мы написали скармливаем серверу сборки Jenkins и сервер сам нам теперь будет собирать *.pdf(ку) после каждого коммита в репозиторий. Автоматически. Здорово! Вы уже любите скрипты cборки?
Плюс в том, что сервер сборки даст вам гарантию, что вы ничего не забыли загрузить в git репозиторий.
Достоинства тандема LaTex + препроцессора
++ Вы получаете полностью конфигурируемый процесс сборки своей брошюры. Благодаря системе сборки Вы можете автоматически синтезировать множество вариаций одного и того же учебника, меняя набор глав и содержание, просто манипулируя переменными окружения в скриптах сборки make. Вам уже нравится сиcтема сборки GNU Make?...
++ Вы получаете полностью бесплатный инструментарий для вёрстки своего дока. Все консольные утилиты свободно скачиваются.
++ Благодаря скриптам Вы можете верстать учебник автоматически на серверах сборки рядом с прошивками. Всё, что от вас требуется это сделать комит в git и, вуаля, у вас новое издание книги.
Недостатки
-- Если вы пишете учебник по Си и вставляете листинги с Си-кодом в LaTex код, то препроцессор будет пытаться вставить include-ы, которых на самом деле нет, и выдаст ошибку. Всё заклинит. Поэтому придется убирать символ # из листингов с кодом и писать справку, что надо подразумевать тут символ #.
Однако это легко решается. Есть ещё более универсальный препроцессор c лаконичным названием: 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)
и получится многострочная макро-подстановка с заменой. Надо реинкарнировать препроцессор m4 из 197x. Тут он даже более применим нежели cpp.
Итоги
Удалось научиться верстать высокодобротную документацию кодом на 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 |
2 |
|
3 |
Вопросы:
Есть ли способ пометить участок кода так, чтобы Си препроцессор его не менял? Чтобы как встретилась строка #include "file.h" так и осталась в первозданном виде.
Как сишным препроцессрором cpp вставить кусок текста макро функцией, сохранив при этом переносы строк?
Существует ли аналог консольной утилиты clang-format только для LaTeX кода?
Как сделать так, чтобы LaTeX проверял русскую грамотность?
Комментарии (11)
maquefel
04.12.2024 11:32Это прям совсем хорошо !
LaTex хорош со всех сторон! Единственное, я не считаю, что его просто читать в исходном виде и для простых текстов предпочитаю Markdown.
--Если вы пишите учебник по Си и вставляете листинги с Си-кодом в LaTex код, то препроцессор будет пытаться вставить include(ы), которых на самом деле нет и выдаст ошибку. Всё заклинит. Поэтому придется убирать символ # из листингов с кодом и писать справку, что надо подразумевать тут символ #.
А почему не использовать lstlisting для кода и тогда не будет этого минуса ?
artptr86
04.12.2024 11:32Почему бы не использовать условные операторы и инклюды из самого латеха, не прибегая к сторонним препроцессорам?
nerudo
04.12.2024 11:32Я всё слегка подзабыл, но ТеХ позволяет создавать свои команды (функции, если хотите), которые могут быть полностью эквивалентны тем макросам, которые вы скармливаете препроцессору.
Sadok
04.12.2024 11:32на LaTeX профессионально программируют так называемые технические писатели
ага. а верстальщики на html программируют. автор не знает самой сути того, о чем пишет.
berez
04.12.2024 11:32Есть ли способ пометить участок кода так, чтобы Си препроцессор его не менял? Чтобы как встретилась строка #include "file.h" так и осталась в первозданном виде.
Нет.
Вам от препроцессора по сути нужно только переменные в тексте менять на актуальные пути. С этим справится более подходящий инструмент (например, sed или awk). Инклюды латекс умеет и сам.
Как сделать так, чтобы LaTeX проверял русскую грамотность?
В википедии пишут вот что:
\usepackage[russian]{babel} % Пакет поддержки русского языка
Включает ли этот "пакет" проверку орфографии - затрудняюсь сказать. Могу предположить, что да (на это намекает слово babel).
Qwertovsky
Вы пробовали Typst? Говорят, он удобнее.
aabzel Автор
С тем же успехом я могу спросить почему не Sphinx?
https://www.sphinx-doc.org/en/master/index.html