Ответ 1
Из моих исследований кажется, что это единственные три способа справиться с этой ситуацией, и я получил каждый из них, чтобы работать, поэтому я думаю, что я просто выберу свою любимую из них.
Я пишу API как модуль ядра, который предоставляет драйверы устройств с различными функциями. Я написал три функции в mycode.c. Затем я построил и загрузил модуль, а затем скопировал mycode.h в <kernel> /include/linux. В драйвере устройства у меня есть #include < linux/mycode.h > и вызовите эти три функции. Но когда я создаю модуль драйвера, я получаю три предупреждения компоновщика, говорящие, что эти функции undefined.
Примечания:
Так ясно, что функции экспортируются правильно, а ядро знает, что и где они находятся. Так почему водитель не может видеть свои определения? Любая идея, что мне не хватает?
EDIT: я нашел здесь некоторую информацию: http://www.kernel.org/doc/Documentation/kbuild/modules.txt
Иногда внешний модуль использует экспортированные символы из другого внешний модуль. kbuild должен иметь полное знание всех символов чтобы не выплескивать предупреждения о символах undefined. Три для этой ситуации существуют решения.
ПРИМЕЧАНИЕ. Рекомендуется использовать метод с файлом kbuild верхнего уровня, но может быть непрактичным в определенных ситуациях.
Использовать файл kbuild верхнего уровня. Если у вас есть два модуля, foo.ko и bar.ko, где foo.ko нужны символы из bar.ko, вы можете использовать общий файл kbuild верхнего уровня, поэтому оба модуля скомпилированы в такой же сборка. Рассмотрим следующий макет каталога:
./foo/ <= contains foo.ko ./bar/ <= contains bar.ko The top-level kbuild file would then look like: #./Kbuild (or ./Makefile): obj-y := foo/ bar/ And executing $ make -C $KDIR M=$PWD will then do the expected and compile both modules with full
знание символов из любого модуля.
Используйте дополнительный файл Module.symvers. Когда создается внешний модуль, создается файл Module.symvers, содержащий все экспортированные символы которые не определены в ядре. Чтобы получить доступ к символам из bar.ko, скопируйте файл Module.symvers из компиляции bar.ko в каталог, где построен foo.ko. Во время сборки модуля, kbuild прочитает файл Module.symvers в каталоге внешний модуль, а когда сборка завершена, новый Создается файл Module.symvers, содержащий сумму всех символов и не является частью ядра.
Используйте переменную "make" KBUILD_EXTRA_SYMBOLS. Если это нецелесообразно Скопируйте Module.symvers из другого модуля, вы можете назначить пространство список файлов в KBUILD_EXTRA_SYMBOLS в вашем файле сборки. Эти файлы будут загружены modpost во время инициализации его таблицы символов.
Но со всеми тремя этими решениями, чтобы любой драйвер мог использовать мой API, ему пришлось бы либо создавать новый Makefile, либо иметь прямой доступ к моему файлу Module.symvers? Это кажется немного неудобным. Я надеялся, что они просто смогут # включить мой заголовочный файл и быть хорошим. Нет ли других альтернатив?
Из моих исследований кажется, что это единственные три способа справиться с этой ситуацией, и я получил каждый из них, чтобы работать, поэтому я думаю, что я просто выберу свою любимую из них.
Минимальный пример QEMU + Buildroot
Я тестировал следующее в полностью воспроизводимой среде QEMU + Buildroot, поэтому, возможно, эта версия рабочей версии поможет вам узнать, что такое wro с вашим кодом.
GitHub upstream сосредоточен на файлах: dep.c | dep2.c | Makefile
dep.c:
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
int lkmc_dep = 0;
EXPORT_SYMBOL(lkmc_dep);
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
printk(KERN_INFO "%d\n", lkmc_dep);
usleep_range(1000000, 1000001);
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
dep2.c:
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
extern int lkmc_dep;
static struct task_struct *kthread;
static int work_func(void *data)
{
while (!kthread_should_stop()) {
usleep_range(1000000, 1000001);
lkmc_dep++;
}
return 0;
}
static int myinit(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
static void myexit(void)
{
kthread_stop(kthread);
}
module_init(myinit)
module_exit(myexit)
Теперь вы можете:
insmod dep.ko
insmod dep2.ko
но Buildroot уже настроил depmod /lib/module/*/depmod
с зависимостью, поэтому этого достаточно, чтобы загрузить оба:
modprobe dep
Если вы используете CONFIG_KALLSYMS_ALL=y
, тогда символ можно увидеть с помощью
grep lkmc_dep /proc/kallsyms