Arlleex 311 September 22, 2023 Posted September 22, 2023 · Report post Я проект разбиваю по каталогам и бывает такое, что несколько файлов ну очень хочется сделать с одинаковыми именами. И если проблему с выбором конкретного файла решить весьма просто - на уровне синтаксиса #include "" или <> (при необходимости еще и с указанием полного пути), то вот из-за одинаковых именований защитных макросов последующие по иерархии подключений файлы не включат свое содержимое. Понятно, что во всем проекте желательно не использовать одинаковые имена заголовков, но это "желательно" иногда не возможно не нарушить. Подправлять имя файла или его защитные макросы "по случаю" не очень хочется, т.к. иногда у меня структура папок немного разъезжается, да и мало ли что... Как пример - у FreeRTOS есть queue.h с его QUEUE_H, projdefs.h с его PROJDEFS_H. Я тоже люблю так кратко именовать файлы и их защитников. Вот только разработчики RTOS пишут не сильно думая об остальном наборе исходников у юзера, а юзеру (мне) уже нужно думать об уникальности защитников. Есть ли в препроцессоре C/C++ возможность клеить имя защитного макроса на основе текущей директории файла? Конкатенация ## для #ifndef не работает, поэтому напрямую не получится. Quote Share this post Link to post Share on other sites More sharing options...
Сергей Борщ 177 September 22, 2023 Posted September 22, 2023 · Report post Для конкретно этой задачи есть #pragma once. Вроде бы обещают, что она даже отличает один и тот же файл, доступный из разных мест по символическим ссылкам с разными именами от другого файла с таким же именем. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 311 September 22, 2023 Posted September 22, 2023 · Report post Только что, Сергей Борщ сказал: Для конкретно этой задачи есть #pragma once. Вроде бы обещают, что она даже отличает один и тот же файл, доступный из разных мест по символической ссылке от другого файла с таким же именем. Вроде да, но узнал я вот, что это не стандартная для реализаций компиляторов штука, ее поведение не строго определено. Даже ARM в описании на свой компилятор убедительно просит не злоупотреблять Не уж то придется писать пре-билд скрипт, который пройдется по всем директориям проекта и переименует у заголовочников их защитников? Quote Share this post Link to post Share on other sites More sharing options...
EdgeAligned 119 September 22, 2023 Posted September 22, 2023 · Report post А никогда не пользовались при создании файла шаблонами файлов с генерацией стандартного наполнения? Эти дефайны могут автоматически генерироваться не только по именам, но и по полному пути относительно проекта Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 311 September 22, 2023 Posted September 22, 2023 · Report post 51 минуту назад, EdgeAligned сказал: А никогда не пользовались при создании файла шаблонами файлов с генерацией стандартного наполнения? Эти дефайны могут автоматически генерироваться не только по именам, но и по полному пути относительно проекта Это у некоторых сред разработки, наверное, так. У меня Keil, но это даже не столь важно, ибо все файлы (свои) я создаю с нуля сам, отдельно от какой-то среды. Quote Share this post Link to post Share on other sites More sharing options...
EdgeAligned 119 September 22, 2023 Posted September 22, 2023 · Report post А я вот очень люблю создавать шаблоны файлов, чтобы они имели однотипное оформление, да и меньше приходится руками копировать необходимое. Например, касательно темы шаблон файла имеет такие строки для автогенерации: ${filecomment} #ifndef ${include_guard_symbol} #define ${include_guard_symbol} .... #endif /* ${include_guard_symbol} */ Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 311 September 22, 2023 Posted September 22, 2023 · Report post 1 час назад, EdgeAligned сказал: А я вот очень люблю создавать шаблоны файлов, чтобы они имели однотипное оформление, да и меньше приходится руками копировать необходимое. Например, касательно темы шаблон файла имеет такие строки для автогенерации: ${filecomment} #ifndef ${include_guard_symbol} #define ${include_guard_symbol} .... #endif /* ${include_guard_symbol} */ А автогенерация на каком уровне? На уровне среды - т.е. перед билдом запускается некий скрпипт, который проходится по каталогам исходников и "редактиурет" их? А как же тогда отслеживать изменения в системах контроля версий? Неплохо, конечно, было бы иметь такой редактор, чтобы вместо выше указанных меток при сохранении файла на диск автоматом подставлял туда некое скрипт-генерированное имя... Quote Share this post Link to post Share on other sites More sharing options...
EdgeAligned 119 September 22, 2023 Posted September 22, 2023 · Report post Нет, не перед билдом, а в процессе создания файла. Там, где вводится имя нового файла, есть список с шаблонами файлов. Так же, сама среда отслеживает переименования файлов и папок и вносит изменения в include_guard_symbol уже созданных файлов. И даже более того - изменяет пути в прописанных инклюдах, да и вообще поддерживает правильный рефакторинг кода. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 311 September 22, 2023 Posted September 22, 2023 · Report post 7 минут назад, EdgeAligned сказал: Нет, не перед билдом, а в процессе создания файла. Там, где вводится имя нового файла, есть список с шаблонами файлов. Так же, сама среда отслеживает переименования файлов и папок и вносит изменения в include_guard_symbol уже созданных файлов. Какая среда? Я не понимаю, в каком виде у Вас лежит на диске само содержимое файла .h? Можете пример привести? Цитата И даже более того - изменяет пути в прописанных инклюдах, да и вообще поддерживает правильный рефакторинг кода. Это для меня лишнее, т.к. не думаю, что эта среда правильно все пропишет (имею в виду так, как это задумываю я). Quote Share this post Link to post Share on other sites More sharing options...
EdgeAligned 119 September 22, 2023 Posted September 22, 2023 · Report post Среда, основанная на Эклипсе 🙂 Раньше она называлась Atollic, сейчас называется CubeIDE. Файлы .c, .cpp, .h, .hpp лежат на диске в самом обычном виде, их можноп ереносить куда угодно и использовать отдельно. Но сам проект содержит конфиг-файл, через который среда и следит за всеми используемыми файлами, а рефакторинг кода проводится самой средой разработки. Ну а рефакторинг кода - это полезная весчь, среда разработки следит за изменениями, которые вы вносите, и изменяет синхронно все вхождения элементов, которые вы изменяете. Пример - это переименование переменных или фукнций, переименования файлов/папок или перемещения их в другие папки. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 311 September 22, 2023 Posted September 22, 2023 · Report post Короче, на ум приходит написать скрипт (на каком-либо языке, да хоть на нативных средствах винды - "батник"), который запускать перед компиляцией проекта. Вызывать скрипты до и после компиляции умеют вообще все системы сборки и IDE уж точно. Так вот, этот скрипт пробежится по всем директориям с исходниками проекта, найдет все заголовочные файлы и скопирует во временную папку TempHeaders рядом с проектом, налету подменяя идентификатор защитного макроса на более длинный, основанный на реальном пути к файлу. Т.е. исходные файлы не будут физически затронуты скриптом. А вот include path среды настроить на эту временную папку TempHeaders и подтягивать заголовки оттуда! Идеально! Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 311 September 22, 2023 Posted September 22, 2023 · Report post Интересно еще вот что (для ознакомления с опытом тутошних коллег) 1. Насколько глубоки директории ваших проектов? Т.е. разбит ли проект на кучку осмысленных папок? Или все почти в одной куче? 2. Если директорий много (проект хорошо логически разбит), есть ли какие-то правила, какие из этих директорий вносить в список include path среды? С одной стороны, чтобы в файлах исходников отвязаться от очень длинных абсолютных или чуть менее, но тоже длинных относительных путей, например, // вместо #include "platform/target/basic/types.h" // писать #include "types.h" нужно каждую папку и каждую подпапку (вообще все места, где есть заголовочные файлы) вносить в список поисковых include path. В чем плюс: не нужно писать длинных путей #include "...". Минус же в том, что если директории проекта реально развесистые, задолбаешься вносить все эти пути в include path в свойствах проекта. С другой стороны, если писать все эти относительные пути (относительно, например, самой "верхней" папки проекта), эти #include "..." будут весьма длинными, да и не особо переносимыми, т.к. при перетаскивании каких-то заголовков в другие папки проект перестанет собираться. Тоже такое себе. Зато если в исходник надо будет подключить несколько заголовочников с одинаковыми именами (но разным содержимым, т.к. они в разных директориях и относятся к разным вещам), никакой путаницы - по пути сразу все понятно что подключается. Может есть какая-то серебряная пуля - в идеале - простое #include "types.h" ищет этот самый types.h в том же каталоге, в котором лежит файл с этой строчкой #include "types.h" (стандартное поведение большинства компиляторов), ну а если надо указать какой-то конкретный файл в длинной директории, эту директорию не надо было писать полностью: например #include "platform/../types.h"? Глянул в репозиторий линукса - там папка include вообще отдельная (мне так не нравится ибо мухи вместе с котлетами перемешаны), а большинство исходников начинаются с #include <linux/file.h>. Т.е. такое чувство, что список путей поиска включений у линукса весьма маленький и основной каталог как раз linux/include/linux где все, повторюсь, в кучу свалено. Quote Share this post Link to post Share on other sites More sharing options...
amaora 31 September 23, 2023 Posted September 23, 2023 · Report post В своем коде не более одного уровня подкаталогов. Компилятору передаю "-I." чтобы отмерял все пути от корня проекта, и не нужно было по разному подключать один и тот же заголовок из разных мест. Бывают исключения когда встроен какой-то сторонний код, путь получается длиннее, но за счет include path не сокращаю. Могу исправить этот сторонний код если совсем плохо вписывается. Например freertos у меня это одна плоская директория с файлами, оригинальную структуру я не сохранял, и еще поправил заголовки, так, чтобы подключать в своем коде только один а в нем уже включены все queue.h и остальное. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 311 September 23, 2023 Posted September 23, 2023 · Report post Понятно ИМХО, править что-то в исходниках стороннего middleware мне видится не очень правильным подходом... Quote Share this post Link to post Share on other sites More sharing options...
gerber 10 September 23, 2023 Posted September 23, 2023 · Report post 14 часов назад, Arlleex сказал: нужно каждую папку и каждую подпапку (вообще все места, где есть заголовочные файлы) вносить в список поисковых include path. В чем плюс: не нужно писать длинных путей #include "...". Минус же в том, что если директории проекта реально развесистые, задолбаешься вносить все эти пути в include path в свойствах проекта. Реально развесистыми могут быть include-директории стороннего ПО, например, SDK, к тому же SDK иногда обновляется, и после обновления SDK что-то может поломаться в сборке проекта и нужно откатить всё обратно на старый SDK, и т. д. Выручает построение include-путей через макросы типа $(SDK_DIR)/include;$(SDK_DIR)/drivers/include Первоначальный список путей для SDK можно стащить из какого-либо example, которые обычно идут с SDK. Quote Share this post Link to post Share on other sites More sharing options...