2016年1月3日 星期日

OpenEmbedded - Writing a recipes/package inherit cmake


基本上inherit cmake跟inherit autotools是差不多的,其實cmake class裡面也是有inherit autotool,比較大的差異是,source file在cmake下是放在${PN}目錄下,即package name下,檔案結構如下:
brook@vista:~/oe-core$ tree meta/recipes-support/brook-cmake
meta/recipes-support/brook-cmake
|-- brook-cmake
|   `-- brook-cmake.patch
`-- brook-cmake_1.0.bb
1 directory, 2 files


brook-cmake.patch就是放置CMakeLists.txt、main.c跟LICENSE,其內容如下:

CMakeLists.txt

cmake_minimum_required (VERSION 2.6)
project(brook-cmake-demo)
add_executable(brook-cmake main.c)
install(TARGETS brook-cmake DESTINATION bin)


main.c

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("hello, cmake\n");
    return 0;
}


brook-cmake_1.0.bb

DESCRIPTION = "Brook CMake Project"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://LICENSE;md5=5ff2bd2dd80c7cc542a6b8de3ee4ff87"

SRC_URI = "file://brook-cmake.patch \
"

inherit cmake

EXTRA_OEMAKE = "-Wall"


下面這裡是多個版本的寫法

其實寫法都一樣,只是patch file的目錄要包含版本號,檔案結構如下:
brook@vista:~/oe-core/meta/recipes-support$ tree brook-cmake
brook-cmake
|-- brook-cmake-1.0
|   `-- brook-cmake.patch
|-- brook-cmake-2.0
|   `-- brook-cmake.patch
|-- brook-cmake_1.0.bb
`-- brook-cmake_2.0.bb


BB檔與patch的內容跟上面都是一樣的
brook@vista:~/oe-core$ cat meta/recipes-support/brook-cmake/brook-cmake_1.0.bb
DESCRIPTION = "Brook CMake Project"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://LICENSE;md5=7e4bf6f59b6da8e57ed5425a10a7310b"

SRC_URI = "file://brook-cmake.patch \
"

inherit cmake

BBCLASSEXTEND = "native"

EXTRA_OEMAKE = "-Wall"

brook@vista:~/oe-core$ cat meta/recipes-support/brook-cmake/brook-cmake_2.0.bb
DESCRIPTION = "Brook CMake Project"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://LICENSE;md5=7e4bf6f59b6da8e57ed5425a10a7310b"

SRC_URI = "file://brook-cmake.patch \
"

inherit cmake

BBCLASSEXTEND = "native"

EXTRA_OEMAKE = "-Wall"

brook@vista:~/oe-core$ cat meta/recipes-support/brook-cmake/brook-cmake-1.0/brook-cmake.patch
From 037c40faba39a11e54f282c3eab5e47a4cf1c7ca Mon Sep 17 00:00:00 2001
From: Brook <rene3210 at gmail.com>
Date: Tue, 27 Sep 2016 20:42:11 +0800
Subject: [PATCH] brook oe demo code

---
 CMakeLists.txt | 5 +++++
 LICENSE        | 1 +
 main.c         | 8 ++++++++
 3 files changed, 14 insertions(+)
 create mode 100644 CMakeLists.txt
 create mode 100644 LICENSE
 create mode 100644 main.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..ee4d6d9
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required (VERSION 2.6)
+project(brook-cmake-demo)
+add_executable(brook-cmake main.c)
+install(TARGETS brook-cmake DESTINATION bin)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0664320
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+"GPLv2"
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..d089aad
--- /dev/null
+++ b/main.c
@@ -0,0 +1,8 @@
+#include 
+
+int main(int argc, char *argv[])
+{
+    printf("hello, cmake 1.0\n");
+    return 0;
+}
+
--
2.7.4

brook@vista:~/oe-core$ cat meta/recipes-support/brook-cmake/brook-cmake-2.0/brook-cmake.patch
From 037c40faba39a11e54f282c3eab5e47a4cf1c7ca Mon Sep 17 00:00:00 2001
From: Brook <rene3210 at gmail.com>
Date: Tue, 27 Sep 2016 20:42:11 +0800
Subject: [PATCH] brook oe demo code

---
 CMakeLists.txt | 5 +++++
 LICENSE        | 1 +
 main.c         | 8 ++++++++
 3 files changed, 14 insertions(+)
 create mode 100644 CMakeLists.txt
 create mode 100644 LICENSE
 create mode 100644 main.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..ee4d6d9
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required (VERSION 2.6)
+project(brook-cmake-demo)
+add_executable(brook-cmake main.c)
+install(TARGETS brook-cmake DESTINATION bin)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0664320
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+"GPLv2"
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..d089aad
--- /dev/null
+++ b/main.c
@@ -0,0 +1,8 @@
+#include 
+
+int main(int argc, char *argv[])
+{
+    printf("hello, cmake 2.0\n");
+    return 0;
+}
+
--
2.7.4


如果沒有特別指定版本的話,會使用最新的,可以透過設定PREFERRED_VERSION_package_name設定特定版本,如
brook@vista:~/oe-core$ grep -H PREFERRED_VERSION build/conf/local.conf
build/conf/local.conf:PREFERRED_VERSION_brook-cmake = "1.0"
相關資訊可以參考Bitbake User Manual/2.3. Preferences and Providers

    參考資料:
  1. CMake 入門




BitBake User Manual - CH3.3. Sharing Functionality


BitBake 有metadata sharing的機制,基本上分為兩類,include file(.inc)跟class file(.bbclass),你可以使用include或require來include .inc檔案,其行為就是會將.inc內容插入include那行的位置中。
include跟require相似,差異是,如果檔案不存在include不會error,但是requre就會,如:
include foo_no_exist.inc
require foo_need_exist.inc

你可以使用iherit來使用class file,使用這指令會去尋找對應的class來使用,如:
inherit autotools

如果每個recipes都需要inherit的話,可以在.conf使用INHERIT指令達成這目的,如:
INHERIT += sanity

example:meta/conf/sanity.conf
# Sanity checks for common user misconfigurations
#
# See sanity.bbclass
#
# Expert users can confirm their sanity with "touch conf/sanity.conf"
BB_MIN_VERSION = "1.27.1"

SANITY_ABIFILE = "${TMPDIR}/abi_version"

SANITY_VERSION ?= "1"
LOCALCONF_VERSION  ?= "1"
LAYER_CONF_VERSION ?= "6"
SITE_CONF_VERSION  ?= "1"

INHERIT += "sanity"


example:meta/classes/sanity.bbclass


    參考資料:
  1. BitBake User Manual




Linux Kernel(15.2)- platform_device_register()之如何调用driver.probe()


Linux Kernel(16.1)- platform_driver_register()之如何调用driver.probe()之後,我們來看如何由platform_device_register调用driver.probe()

int platform_device_register(struct platform_device *pdev)
{
    device_initialize(&pdev->dev);
    arch_setup_pdev_archdata(pdev);
    return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);


int platform_device_add(struct platform_device *pdev)
{
    int i, ret;

    if (!pdev)
        return -EINVAL;

    if (!pdev->dev.parent)
        pdev->dev.parent = &platform_bus;

    pdev->dev.bus = &platform_bus_type;

    switch (pdev->id) {
    default:
        dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
        break;
    case PLATFORM_DEVID_NONE:
        dev_set_name(&pdev->dev, "%s", pdev->name);
        break;
    case PLATFORM_DEVID_AUTO:
        /*
         * Automatically allocated device ID. We mark it as such so
         * that we remember it must be freed, and we append a suffix
         * to avoid namespace collision with explicit IDs.
         */
        ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
        if (ret < 0)
            goto err_out;
        pdev->id = ret;
        pdev->id_auto = true;
        dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
        break;
    }

    for (i = 0; i < pdev->num_resources; i++) {
        struct resource *p, *r = &pdev->resource[i];

        if (r->name == NULL)
            r->name = dev_name(&pdev->dev);

        p = r->parent;
        if (!p) {
            if (resource_type(r) == IORESOURCE_MEM)
                p = &iomem_resource;
            else if (resource_type(r) == IORESOURCE_IO)
                p = &ioport_resource;
        }

        if (p && insert_resource(p, r)) {
            dev_err(&pdev->dev, "failed to claim resource %d\n", i);
            ret = -EBUSY;
            goto failed;
        }
    }

    pr_debug("Registering platform device '%s'. Parent at %s\n",
         dev_name(&pdev->dev), dev_name(pdev->dev.parent));

    ret = device_add(&pdev->dev);
    if (ret == 0)
        return ret;

 failed:
    if (pdev->id_auto) {
        ida_simple_remove(&platform_devid_ida, pdev->id);
        pdev->id = PLATFORM_DEVID_AUTO;
    }

    while (--i >= 0) {
        struct resource *r = &pdev->resource[i];
        if (r->parent)
            release_resource(r);
    }

 err_out:
    return ret;
}


int device_add(struct device *dev) 
{
    struct device *parent = NULL;
    struct kobject *kobj;
    struct class_interface *class_intf;
    int error = -EINVAL;

    dev = get_device(dev);
    if (!dev)
        goto done;

    if (!dev->p) {
        error = device_private_init(dev);
        if (error)
            goto done;
    }

    /*
     * for statically allocated devices, which should all be converted
     * some day, we need to initialize the name. We prevent reading back
     * the name, and force the use of dev_name()
     */
    if (dev->init_name) {
        dev_set_name(dev, "%s", dev->init_name);
        dev->init_name = NULL;
    }

    /* subsystems can specify simple device enumeration */
    if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
        dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

    if (!dev_name(dev)) {
        error = -EINVAL;
        goto name_error;
    }

    pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

    parent = get_device(dev->parent);
    kobj = get_device_parent(dev, parent);
    if (kobj)
        dev->kobj.parent = kobj;

    /* use parent numa_node */
    if (parent)
        set_dev_node(dev, dev_to_node(parent));

    /* first, register with generic layer. */
    /* we require the name to be set before, and pass NULL */
    error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
    if (error)
        goto Error;

    /* notify platform of device entry */
    if (platform_notify)
        platform_notify(dev);

    error = device_create_file(dev, &dev_attr_uevent);
    if (error)
        goto attrError;

    error = device_add_class_symlinks(dev);
    if (error)
        goto SymlinkError;
    error = device_add_attrs(dev);
    if (error)
        goto AttrsError;
    error = bus_add_device(dev);
    if (error)
        goto BusError;
    error = dpm_sysfs_add(dev);
    if (error)
        goto DPMError;
    device_pm_add(dev);

    if (MAJOR(dev->devt)) {
        error = device_create_file(dev, &dev_attr_dev);
        if (error)
            goto DevAttrError;

        error = device_create_sys_dev_entry(dev);
        if (error)
            goto SysEntryError;

        devtmpfs_create_node(dev);
    }

    /* Notify clients of device addition.  This call must come
     * after dpm_sysfs_add() and before kobject_uevent().
     */
    if (dev->bus)
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                         BUS_NOTIFY_ADD_DEVICE, dev);

    kobject_uevent(&dev->kobj, KOBJ_ADD);
    bus_probe_device(dev);
    if (parent)
        klist_add_tail(&dev->p->knode_parent,
                   &parent->p->klist_children);

    if (dev->class) {
        mutex_lock(&dev->class->p->mutex);
        /* tie the class to the device */
        klist_add_tail(&dev->knode_class,
                   &dev->class->p->klist_devices);

        /* notify any interfaces that the device is here */
        list_for_each_entry(class_intf,
                    &dev->class->p->interfaces, node)
            if (class_intf->add_dev)
                class_intf->add_dev(dev, class_intf);
        mutex_unlock(&dev->class->p->mutex);
    }
done:
    put_device(dev);
    return error;
 SysEntryError:
    if (MAJOR(dev->devt))
        device_remove_file(dev, &dev_attr_dev);
 DevAttrError:
    device_pm_remove(dev);
    dpm_sysfs_remove(dev);
 DPMError:
    bus_remove_device(dev);
 BusError:
    device_remove_attrs(dev);
 AttrsError:
    device_remove_class_symlinks(dev);
 SymlinkError:
    device_remove_file(dev, &dev_attr_uevent);
 attrError:
    kobject_uevent(&dev->kobj, KOBJ_REMOVE);
    kobject_del(&dev->kobj);
 Error:
    cleanup_device_parent(dev);
    put_device(parent);
name_error:
    kfree(dev->p);
    dev->p = NULL;
    goto done;
}


void bus_probe_device(struct device *dev)
{
    struct bus_type *bus = dev->bus;
    struct subsys_interface *sif;

    if (!bus)
        return;

    if (bus->p->drivers_autoprobe)
        device_initial_probe(dev);

    mutex_lock(&bus->p->mutex);
    list_for_each_entry(sif, &bus->p->interfaces, node)
        if (sif->add_dev)
            sif->add_dev(dev, sif);
    mutex_unlock(&bus->p->mutex);
}


void device_initial_probe(struct device *dev)
{
    __device_attach(dev, true);
}


static int __device_attach(struct device *dev, bool allow_async)
{
    int ret = 0;

    device_lock(dev);
    if (dev->driver) {
        if (klist_node_attached(&dev->p->knode_driver)) {
            ret = 1;
            goto out_unlock;
        }
        ret = device_bind_driver(dev);
        if (ret == 0)
            ret = 1;
        else {
            dev->driver = NULL;
            ret = 0;
        }
    } else {
        struct device_attach_data data = {
            .dev = dev,
            .check_async = allow_async,
            .want_async = false,
        };

        if (dev->parent)
            pm_runtime_get_sync(dev->parent);

        ret = bus_for_each_drv(dev->bus, NULL, &data,
                    __device_attach_driver);
        if (!ret && allow_async && data.have_async) {
            /*
             * If we could not find appropriate driver
             * synchronously and we are allowed to do
             * async probes and there are drivers that
             * want to probe asynchronously, we'll
             * try them.
             */
            dev_dbg(dev, "scheduling asynchronous probe\n");
            get_device(dev);
            async_schedule(__device_attach_async_helper, dev);
        } else {
            pm_request_idle(dev);
        }

        if (dev->parent)
            pm_runtime_put(dev->parent);
    }
out_unlock:
    device_unlock(dev);
    return ret;
}


static int __device_attach_driver(struct device_driver *drv, void *_data)
{
    struct device_attach_data *data = _data;
    struct device *dev = data->dev;
    bool async_allowed;

    /*
     * Check if device has already been claimed. This may
     * happen with driver loading, device discovery/registration,
     * and deferred probe processing happens all at once with
     * multiple threads.
     */
    if (dev->driver)
        return -EBUSY;

    if (!driver_match_device(drv, dev))
        return 0;

    async_allowed = driver_allows_async_probing(drv);

    if (async_allowed)
        data->have_async = true;

    if (data->check_async && async_allowed != data->want_async)
        return 0;

    return driver_probe_device(drv, dev);
}


static inline int driver_match_device(struct device_driver *drv,
                      struct device *dev)
{
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}





熱門文章