Почему в проектах используется ключ -I с учетом опасностей? - PullRequest
0 голосов
/ 05 ноября 2018

Читая мелкий шрифт переключателя -I в GCC, я довольно шокирован, обнаружив, что его использование в системе переопределений командной строки включает в себя. Из документов препроцессора

"Вы можете использовать -I для переопределения файла системного заголовка, заменив свою собственную версию, так как эти каталоги ищутся перед стандартными каталогами файлов системного заголовка."

Кажется, они не лгут. В двух разных системах Ubuntu с GCC 7, если я создаю файл endian.h:

#error "This endian.h shouldn't be included"

... и затем в том же каталоге создайте main.cpp (или main.c, такая же разница):

#include <stdlib.h>
int main() {}

Затем компиляция с g++ main.cpp -I. -o main (или лязгом, такая же разница) дает мне:

In file included from /usr/include/x86_64-linux-gnu/sys/types.h:194:0,
                 from /usr/include/stdlib.h:394,
                 from /usr/include/c++/7/cstdlib:75,
                 from /usr/include/c++/7/stdlib.h:36,
                 from main.cpp:1:
./endian.h:1:2: error: #error "This endian.h shouldn't be included"

Итак, stdlib.h включает этот файл types.h, который в строке 194 просто говорит #include <endian.h>. Мое очевидное заблуждение (и, возможно, чужое) заключалось в том, что угловые скобки предотвратили бы это, но - я сильнее, чем я думал.

Хотя не достаточно достаточно , потому что вы даже не можете исправить это, предварительно введя / usr / include в командной строке, потому что:

"Если стандартный системный каталог включения или каталог, указанный с помощью -isystem, также указан с -I, опция -I игнорируется. Каталог по-прежнему ищется, но как системный каталог на его нормальное положение в системе включает цепь. "

Действительно, подробный вывод для g++ -v main.cpp -I/usr/include -I. -o main оставляет / usr / include внизу списка:

#include "..." search starts here:
#include <...> search starts here:
 .
 /usr/include/c++/7
 /usr/include/x86_64-linux-gnu/c++/7
 /usr/include/c++/7/backward
 /usr/lib/gcc/x86_64-linux-gnu/7/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include

Цвет меня удивил. Я думаю, чтобы сделать это вопрос:

Какая законная причина для большинства проектов использовать -I, учитывая эту чрезвычайно серьезную проблему? Вы можете переопределить произвольные заголовки в системах на основе случайных коллизий имен. Разве не все должны использовать -iquote вместо этого?

Ответы [ 4 ]

0 голосов
/ 05 ноября 2018

Я считаю, что это -I опасно - ложь. Язык оставляет поиск файлов заголовков с любой формой #include в достаточной степени определенной реализацией, поэтому небезопасно использовать файлы заголовков, которые вообще конфликтуют с именами стандартных файлов заголовков. Просто воздержитесь от этого.

0 голосов
/ 05 ноября 2018

Оглядываясь на руководства GCC, это выглядит как -iquote, а другие опции были добавлены только в GCC 4: https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Directory-Options.html#Directory%20Options

Таким образом, использование "-I", вероятно, представляет собой некоторую комбинацию: привычки, ленивости, обратной совместимости, незнания новых опций, совместимости с другими компиляторами.

Решение состоит в том, чтобы «пространство имен» ваших заголовочных файлов, поместив их в подкаталоги. Например, поместите свой конечный заголовок в "include/mylib/endian.h", затем добавьте "-Iinclude" в командную строку, и вы можете #include "mylib/endian.h", который не должен конфликтовать с другими библиотеками или системными библиотеками.

0 голосов
/ 05 ноября 2018

Очевидным случаем является кросс-компиляция. GCC немного страдает от исторического предположения UNIX, что вы всегда компилируете для своей локальной системы или, по крайней мере, чего-то очень близкого. Вот почему заголовочные файлы компилятора находятся в корневом каталоге системы. Чистый интерфейс отсутствует.

Для сравнения, Windows не предполагает компилятор, а компиляторы Windows не предполагают, что вы нацелены на локальную систему. Вот почему вы можете иметь набор компиляторов и набор SDK.

Теперь в кросс-компиляции GCC ведет себя гораздо больше как компилятор для Windows. Он больше не предполагает, что вы намереваетесь использовать заголовки локальной системы, но позволяет вам точно указать, какие заголовки вы хотите. И, очевидно, то же самое относится и к библиотекам, на которые вы ссылаетесь.

Теперь обратите внимание, что когда вы делаете это, набор сменных заголовков предназначен для перехода на top базовой системы. Вы можете не указывать заголовки в наборе замен, если их реализация будет идентичной. Например. Скорее всего, <complex.h> это то же самое. В реализации сложных чисел не так много изменений. Однако вы не можете произвольно заменить внутренние биты реализации, такие как <endian.h>.

TL, DR: этот вариант, если для людей, которые знают, что делают. «Быть ​​небезопасным» не является аргументом для целевой аудитории.

0 голосов
/ 05 ноября 2018

Какие существуют законные причины для -I свыше -iquote? -I стандартизирован (по крайней мере, POSIX ), а -iquote нет. (Практически я использую -I, потому что tinycc (один из компиляторов, с которыми я хочу компилировать мой проект) не поддерживает -iquote.)

Как проекты справляются с -I с учетом опасностей? Вы включили бы включенные в каталог включения и используете -I, чтобы добавить каталог, содержащий этот каталог.

  • файловая система: includes/mylib/endian.h
  • командная строка: -Iincludes
  • C / C ++ файл: #include "mylib/endian.h" //or <mylib/endian.h>

При этом, если вы не конфликтуете с именем mylib, вы не конфликтуете (по крайней мере, в отношении имен заголовков).

...