summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaszlo Papp <lpapp@kde.org>2013-10-25 00:22:16 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-28 15:36:30 +0100
commitd4c0885256f3005a8758153c1b82d467ee87478d (patch)
treedb5a0db2ecfcaf77e60497bf4f136ec05c01cc2a
parent609b5c9fa7ba47157e1e1831270e2a2bd926b460 (diff)
downloadqtserialport-d4c0885256f3005a8758153c1b82d467ee87478d.tar.gz
Add support for loading udev at run-time
QtSerialPort is linked against udev by default if the development files can be detected on the system. The reason for this is that, it is more common to link against udev than loading it at run-time. People will usually use distribution packages where there cannot be inconsistency between different versions, and hence ABI breaks, etc. The relevant LINK_LIBUDEV variable will be set. This can be overridden by defining LOAD_LIBUDEV for qmake: qmake "DEFINES += LOAD_LIBUDEV" -r It is also worth noting that the common code is separated into a private header, and it can be included for either type of libudev usage. There is no need for its user to handle the compile-time linking or run-time loading separately on top of that. Task-number: QTBUG-34329 Change-Id: I45ffaaede2a74498587a6452fbe3fec7eaf83483 Reviewed-by: Sergey Belyashov <Sergey.Belyashov@gmail.com> Reviewed-by: Kai Koehne <kai.koehne@digia.com> Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com>
-rw-r--r--src/serialport/qserialportinfo_unix.cpp14
-rw-r--r--src/serialport/qtudev_p.h144
-rw-r--r--src/serialport/serialport-lib.pri4
3 files changed, 154 insertions, 8 deletions
diff --git a/src/serialport/qserialportinfo_unix.cpp b/src/serialport/qserialportinfo_unix.cpp
index ea5a1b3..44a4a2c 100644
--- a/src/serialport/qserialportinfo_unix.cpp
+++ b/src/serialport/qserialportinfo_unix.cpp
@@ -49,11 +49,8 @@
#ifndef Q_OS_MAC
-#ifdef HAVE_LIBUDEV
-extern "C"
-{
-#include <libudev.h>
-}
+#if defined(LINK_LIBUDEV) || defined(LOAD_LIBUDEV)
+#include "qtudev_p.h"
#else
#include <QtCore/qdir.h>
#include <QtCore/qstringlist.h>
@@ -65,7 +62,7 @@ QT_BEGIN_NAMESPACE
#ifndef Q_OS_MAC
-#ifndef HAVE_LIBUDEV
+#if !defined(LINK_LIBUDEV) && !defined(LOAD_LIBUDEV)
static inline const QStringList& filtersOfDevices()
{
@@ -218,6 +215,11 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
{
+#ifdef LOAD_LIBUDEV
+ static bool symbolsResolved = resolveSymbols();
+ if (!symbolsResolved)
+ return QList<QSerialPortInfo>();
+#endif
QList<QSerialPortInfo> serialPortInfoList;
// White list for devices without a parent
diff --git a/src/serialport/qtudev_p.h b/src/serialport/qtudev_p.h
new file mode 100644
index 0000000..2619f8e
--- /dev/null
+++ b/src/serialport/qtudev_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSerialPort module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTUDEV_P_H
+#define QTUDEV_P_H
+
+#ifdef LINK_LIBUDEV
+extern "C"
+{
+#include <libudev.h>
+}
+#elif defined(LOAD_LIBUDEV)
+#include <QtCore/qlibrary.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qdebug.h>
+
+#define GENERATE_SYMBOL_VARIABLE(returnType, symbolName, ...) \
+ typedef returnType (*fp_##symbolName)(__VA_ARGS__); \
+ fp_##symbolName symbolName;
+
+#define RESOLVE_SYMBOL(symbolName) \
+ symbolName = (fp_##symbolName)resolveSymbol(#symbolName); \
+ if (!symbolName) \
+ return false;
+
+struct udev;
+
+#define udev_list_entry_foreach(list_entry, first_entry) \
+ for (list_entry = first_entry; \
+ list_entry != NULL; \
+ list_entry = udev_list_entry_get_next(list_entry))
+
+struct udev_device;
+struct udev_enumerate;
+struct udev_list_entry;
+
+GENERATE_SYMBOL_VARIABLE(struct ::udev *, udev_new);
+GENERATE_SYMBOL_VARIABLE(struct ::udev_enumerate *, udev_enumerate_new, struct ::udev *)
+GENERATE_SYMBOL_VARIABLE(int, udev_enumerate_add_match_subsystem, struct udev_enumerate *, const char *)
+GENERATE_SYMBOL_VARIABLE(int, udev_enumerate_scan_devices, struct udev_enumerate *)
+GENERATE_SYMBOL_VARIABLE(struct udev_list_entry *, udev_enumerate_get_list_entry, struct udev_enumerate *)
+GENERATE_SYMBOL_VARIABLE(struct udev_list_entry *, udev_list_entry_get_next, struct udev_list_entry *)
+GENERATE_SYMBOL_VARIABLE(struct udev_device *, udev_device_new_from_syspath, struct udev *udev, const char *syspath)
+GENERATE_SYMBOL_VARIABLE(const char *, udev_list_entry_get_name, struct udev_list_entry *)
+GENERATE_SYMBOL_VARIABLE(const char *, udev_device_get_devnode, struct udev_device *)
+GENERATE_SYMBOL_VARIABLE(const char *, udev_device_get_sysname, struct udev_device *)
+GENERATE_SYMBOL_VARIABLE(struct udev_device *, udev_device_get_parent, struct udev_device *)
+GENERATE_SYMBOL_VARIABLE(const char *, udev_device_get_subsystem, struct udev_device *)
+GENERATE_SYMBOL_VARIABLE(const char *, udev_device_get_property_value, struct udev_device *, const char *)
+GENERATE_SYMBOL_VARIABLE(void, udev_device_unref, struct udev_device *)
+GENERATE_SYMBOL_VARIABLE(void, udev_enumerate_unref, struct udev_enumerate *)
+GENERATE_SYMBOL_VARIABLE(void, udev_unref, struct udev *)
+
+QLibrary udevLibrary;
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+inline QFunctionPointer resolveSymbol(const char *symbolName)
+{
+ QFunctionPointer symbolFunctionPointer = udevLibrary.resolve(symbolName);
+#else
+inline void *resolveSymbol(const char *symbolName)
+{
+ void *symbolFunctionPointer = udevLibrary.resolve(symbolName);
+#endif
+ if (!symbolFunctionPointer)
+ qWarning("Failed to resolve the udev symbol: %s", symbolName);
+
+ return symbolFunctionPointer;
+}
+
+inline bool resolveSymbols()
+{
+ if (!udevLibrary.isLoaded()) {
+ udevLibrary.setFileNameAndVersion(QLatin1String("udev"), 1);
+ if (!udevLibrary.load()) {
+ udevLibrary.setFileNameAndVersion(QLatin1String("udev"), 0);
+ if (!udevLibrary.load()) {
+ qWarning("Failed to load the library: %s, supported version(s): %i and %i", qPrintable(udevLibrary.fileName()), 1, 0);
+ return false;
+ }
+ }
+ }
+
+ RESOLVE_SYMBOL(udev_new)
+ RESOLVE_SYMBOL(udev_enumerate_new)
+ RESOLVE_SYMBOL(udev_enumerate_add_match_subsystem)
+ RESOLVE_SYMBOL(udev_enumerate_scan_devices)
+ RESOLVE_SYMBOL(udev_enumerate_get_list_entry)
+ RESOLVE_SYMBOL(udev_list_entry_get_next)
+ RESOLVE_SYMBOL(udev_device_new_from_syspath)
+ RESOLVE_SYMBOL(udev_list_entry_get_name)
+ RESOLVE_SYMBOL(udev_device_get_devnode)
+ RESOLVE_SYMBOL(udev_device_get_sysname)
+ RESOLVE_SYMBOL(udev_device_get_parent)
+ RESOLVE_SYMBOL(udev_device_get_subsystem)
+ RESOLVE_SYMBOL(udev_device_get_property_value)
+ RESOLVE_SYMBOL(udev_device_unref)
+ RESOLVE_SYMBOL(udev_enumerate_unref)
+ RESOLVE_SYMBOL(udev_unref)
+
+ return true;
+}
+
+#endif
+
+#endif
diff --git a/src/serialport/serialport-lib.pri b/src/serialport/serialport-lib.pri
index 78f4139..f9d0af3 100644
--- a/src/serialport/serialport-lib.pri
+++ b/src/serialport/serialport-lib.pri
@@ -1,10 +1,10 @@
INCLUDEPATH += $$PWD
-unix {
+!contains(DEFINES, LOAD_LIBUDEV): unix {
CONFIG += link_pkgconfig
packagesExist(libudev) {
- DEFINES += HAVE_LIBUDEV
+ DEFINES += LINK_LIBUDEV
PKGCONFIG += libudev
}
}