วิธีรวมไฟล์ส่วนหัวในเครื่องในโมดูลเคอร์เนลของ linux


17

ว่าฉันมีโมดูลที่mymodมีไฟล์ต้นฉบับดังนี้

src / mod / mymod.c
src / inc / mymod.h

ฉันพยายามที่จะรวม mymod.h ดังต่อไปนี้

#include <mymod.h>

makefile ของฉันมีEXTRA_CFLAGS= -I$(shell pwd)/../inc/แต่เมื่อเคอร์เนลทำฉันได้รับข้อผิดพลาดที่ระบุ:

ไม่พบ mymod.h

เหตุผลน่าจะเป็นที่เมื่อโมดูลเคอร์เนลทำคำสั่งนี้ได้รับการเรียกใช้จาก makefile: (ใช้makeV1):

make -C <path/to/linux/src> M=<path/to/mymod> modules

ในผลงานอื่น ๆ ของฉัน$(shell pwd)Got <path/to/linux>ขยายไป นี่ไม่ใช่สิ่งที่ฉันต้องการ ฉันจะระบุ-Iพารามิเตอร์ให้ชี้ไปที่แผนภูมิต้นไม้src/incของฉันได้mymodอย่างไร

คำตอบ:


19

makefiles เคอร์เนล Linux ใช้เฟรมเวิร์ก Kbuild แม้ว่าสิ่งเหล่านี้จะถูกตีความโดย GNU make แต่ Kbuild ประกอบด้วยชุดของแมโครขนาดใหญ่ที่มีข้อกำหนดการใช้งานที่แปลกประหลาดดังนั้นแนวทาง makefile ทั่วไปจึงไม่มีผลบังคับใช้ สิ่งที่ดีเกี่ยวกับ Kbuild คือคุณต้องมีหม้อไอน้ำน้อยมากเมื่อพิจารณาถึงความซับซ้อนของงาน

Kbuild Documentation/kbuildการบันทึกไว้ในแหล่งเมล็ดใน ในฐานะนักเขียนโมดูลคุณควรอ่านเป็นพิเศษmodules.txt(และอย่างน้อยก็อ่านผ่าน ๆ )

สิ่งที่คุณทำอยู่ตอนนี้ไม่ทำงานเพราะ$(shell pwd)ถูกขยายเมื่อใช้EXTRA_CFLAGSตัวแปร เนื่องจาก makefile เรียกใช้จากแผนผังซอร์สเคอร์เนลแทนที่จะมาจากไดเรกทอรีของโมดูลของคุณ (นี่คือหนึ่งในหลาย ๆ แง่มุมที่ไม่ได้ทำให้เห็นได้ชัดของ Kbuild) มันจึงรวบรวมไดเรกทอรีที่ไม่ถูกต้อง

modules.txtสำนวนอย่างเป็นทางการสำหรับการระบุรวมไดเรกทอรีในโมดูลออกจากต้นไม้ที่อยู่ใน§5.3ของ srcตัวแปรมีการตั้งค่าไปยังไดเรกทอรีระดับบนสุดโมดูลของคุณ ดังนั้น:

EXTRA_CFLAGS := -I$(src)/src/inc

โปรดทราบว่าการประกาศนี้ควรอยู่ในไฟล์ที่เรียกKbuildที่รูทของทรีโมดูลของคุณ (คุณอาจต้องการพิจารณาว่าsrcไดเรกทอรีเป็นรูทของโมดูลทรีของคุณถ้าเป็นเช่นนั้นให้ใส่ที่Kbuildนั่นและแทนที่ค่าข้างต้นด้วย-I$(src)/inc) นอกจากนี้ยังเป็นไปได้ที่จะใส่ไว้ในMakefileแต่ทราบว่าคำนิยามนี้ (ตราบใดที่สิ่งอื่นที่ใช้เฉพาะเมื่อมีการสร้างเคอร์เนลโมดูล) ifeq ($(KERNELRELEASE),)ควรจะอยู่ในคำสั่งเงื่อนไข modules.txtดู§4.1ของ

หากคุณไม่ได้มีไฟล์อยู่แล้วและต้องการที่จะสลับไปมีหนึ่งอ่าน§4.1ของKbuild modules.txtการมีKbuildไฟล์แยกต่างหากจะชัดเจนขึ้นเล็กน้อย อย่าใส่อะไรที่ใช้กับเคอร์เนลใน Makefile make -C $(KERNELDIR) M=$(pwd)หลักของคุณนอกเหนือจากกฎเพื่อโทร ในKbuildขั้นต่ำที่คุณต้องการคือรายการของโมดูลที่คุณกำลังสร้าง (มักจะเป็นเพียงหนึ่ง) และรายการของไฟล์ที่จะรวมในโมดูลของคุณรวมถึงการประกาศการพึ่งพา:

EXTRA_CFLAGS := -I$(src)/inc
obj-m := mymod.o
mymod-y := $(src)/mod/mymod.o
$(src)/mod/mymod.o: $(src)/inc/mymod.h

ฉันไม่สามารถอัปเดตโพสต์ได้เนื่องจากฉันมีชื่อเสียงไม่เพียงพอ
Om Narasimhan

1
@Om Narasimhan: หากสิ่งนี้ช่วยให้คุณเข้าใจวิธีการแก้ปัญหาคุณควรทำเครื่องหมายคำตอบว่ายอมรับ
CVn

1

โดยปกติแล้ว#includeไฟล์ที่มีพา ธ ที่สัมพันธ์กับไดเรกทอรีของซอร์สโค้ดปัจจุบันคือการใช้เครื่องหมายคำพูดแทนที่จะเป็นวงเล็บเหลี่ยม:

#include <stdio.h>
#include "mygreatfunctions.h"

ในกรณีนี้เป็นครั้งแรกที่#includeจะอ้างอิงคอมไพเลอร์รวมถึงเส้นทาง (ซึ่งในกรณีของ GCC ที่ถูกควบคุมโดยการค้นหา-Iสวิตช์บรรทัดคำสั่ง) #includeในขณะที่สองจะมองในไดเรกทอรีที่มีแฟ้มแหล่งที่มาด้วย

เส้นทางดังกล่าวสามารถเป็นญาติได้เช่นกัน ดังนั้นใน src / mod / mymod.c คุณสามารถพูดได้:

#include "../inc/mymod.h"

และควร "เพียงแค่ทำงาน"

ฉันไม่รู้ว่านี่เป็นวิธีปฏิบัติทั่วไปในเคอร์เนลลินุกซ์หรือไม่ แต่แน่นอนว่ามันดีกว่าการรวมตัวกับพา ธ รวมซึ่งอาจมีผลข้างเคียงที่ไม่ได้ตั้งใจจำนวนมาก


1
คำแนะนำที่ดีโดยทั่วไปอย่างไรก็ตาม makefiles เคอร์เนลของ Linux นั้นแปลกมาก พวกเขาเรียกใช้แมโครที่ซับซ้อนที่เรียกว่า Kbuild บ่อยครั้งที่ดีที่สุดที่จะปฏิบัติต่อ Kbuild เป็นภาษาที่เกือบจะเหมือน แต่ไม่แตกต่างจากภาษาอื่นอย่างสิ้นเชิง
Gilles 'หยุดความชั่วร้าย'

1
แน่นอน แต่พฤติกรรมของคอมไพเลอร์ C ในการค้นหา <foo> ในชุดไดเรกทอรีที่กำหนดค่าไว้บางส่วนและสำหรับ "bar" มองไปที่ไดเรกทอรีปัจจุบันก่อนจากนั้นกลับไปที่เส้นทางที่กล่าวถึงก่อนหน้านี้จะไม่เปลี่ยนแปลงตามสิ่งที่แปลกประหลาด คอมไพเลอร์ในสถานที่แรก
vonbrand
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.