Как скрыть служебные функции от пользователя при компиляции библиотеки в си?

Я хочу скомпилировать библиотеку, но скрыть некоторые служебные функции. Я не могу просто засунуть их в .c файлы, потому что эти функции используются в разных модулях библиотеки, но я не хочу чтоб они были видны пользователю. Как это грамотно сделать?

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

multiplier.h

int multiplication(int a, int b);

multiplier.c

#include "multiplier.h"

int multiplication(int a, int b) {
    return a * b;
}

summator.h

int sum(int a, int b);

summator.c

#include "summator.h"

int sum(int a, int b){
    return a + b;
}

mult_summ.h

#include "multiplier.h"
#include "summator.h"

int mult_sum(int a, int b);

mult_summ.c

#include "mult_summ.h"

int mult_sum(int a, int b) {
    return sum(multiplication(a, b), sum(a, b));
}

Я хочу, чтоб пользователь видел только функцию в файле mult_sum.h, как мне это сделать?? Вот мой cmake файл

cmake_minimum_required(VERSION 3.17)
project(untitled2 C)
set(CMAKE_C_STANDARD 11)
include_directories(inc)
add_library(math STATIC src/summator.c src/multiplication.c src/mult_summ.c)

Ответы (1 шт):

Автор решения: Fat-Zer

Статическая библиотека — это просто архив с объектными файлами, так что полностью спрятать функции, которые используются в других модулях компиляции принципиально не получится.

Из нормальных решений — отдать пользователю только один хедр — mult_summ.h. И написать в нём что-то вроде «если кто-то будет использовать функции из библиотеки, не описанные в данном файле, то мы не ручаемся за последствия, а также можем уволить и/или засудить виновника».

Кроме того хорошей практикой будет дать какие-либо специфические имена внутренним функциям, дабы не возник конфликт с пользовательскими функциями, например начать имя с подчёркивания (_), имени библиотеки и/или добавить какой-нить суффикс, например _internal_.

Среди менее рациональных вариантом я бы выделил:

  • слить все *.c файлы в один и объявить функции которые не должны экспортироваться, как статические.
  • заставить компилятор встраивать все функции, которые не должны быть экспортированы

Для динамических библиотек можно объявить некоторые символы скрытыми. Для PE-EXE (dll) все символы по умолчанию являются скрытыми, а для ELF это делается как-то так. В cmake это будет выглядеть как:

add_library(math SHARED src/summator.c src/multiplication.c src/mult_summ.c)
set_target_properties(math PROPERTIES C_VISIBILITY_PRESET hidden)
→ Ссылка