62 Commits

Author SHA1 Message Date
hayodea 8237cd62da xcbXorg: Rename api tag to "xcb", instead of "xcb-xorg" 2025-01-14 23:39:22 -04:00
hayodea 181759ff26 Docs:xcbXorg: Document apiParams, providerParams and devSelector
Add documentation that explains how to construct a devSpec for matching
and attaching windows from Xorg using the xcbXorg sense API lib.
2025-01-14 23:29:26 -04:00
hayodea 7b79636681 devSpec:yacc: Put param after params 2025-01-14 23:14:19 -04:00
hayodea 4dee8c62c9 devSpec:yacc: We now print out the current lex token string
We used some preprocessor logic to enable access to yytext and now
we can have verbose, useful error messages from the parser :)
2025-01-14 23:13:02 -04:00
hayodea 9a9f5058ed devSpec: allow backslash escaped whitespace in STRING tokens
This allows us to use spaces when specifying window name selectors.
Which is very convenient and cool.
2025-01-14 23:11:30 -04:00
hayodea ff56bfce04 xcbXorg: Indentation 2025-01-14 21:12:41 -04:00
hayodea 098b79b331 xcbXorg: Add new param keys: devsubstring, devstring
* devsubstring: substring match on window name.
* devstring: exact match on window name
2025-01-14 21:11:47 -04:00
hayodea 20154d1e95 xcbXorg: Use apiParams to choose match method for window attachment
We now use param keys in the API params to choose what type of ID
the deviceSelector holds, and how to match it.

* dev-id/devid: matches by ID.
* dev-substr/dev-substring/devsubstr: Matches window name by substring.
* dev-string/devstr/dev-str: matches window name by exact whole string.
2025-01-14 20:59:28 -04:00
hayodea 64baa7906b xcbXorg: Implement window search by ID and name
The name search doesn't quite seem to work, but we captured all 4
of our regularly active windows (including the browser!!!) using
window IDs.
2025-01-14 20:22:12 -04:00
hayodea d31530e0bd xcbXorg: indentation 2025-01-14 17:01:16 -04:00
hayodea a80db04dac xcbXorg: Replace display+screen with XConnectionIdentifier 2025-01-14 16:58:22 -04:00
hayodea 0a6f7feeca xcbXorg: Now properly connects to requested display *AND* screen
We append the desired screen number to the connection string.
2025-01-14 16:50:37 -04:00
hayodea 091d7ceeba xcbXorg: Parse devSpec params, connect to Xorg displays
This patch adds some nicely weighty code for connecting to X displays
and managing those connections. Attaching devices will automatically
connect to their required X display. Removing all devices dependent
on a given X display connection will also disconnect from that
Xdisplay.
2025-01-14 14:17:05 -04:00
hayodea cfdeb17639 SenseApiMgr: Add doxygen comment explaining the lib search priorities 2025-01-14 14:17:05 -04:00
hayodea aaae3dcbb2 DevSpec: Grammar now parses params as key[=[val]]
* Updated docs to reflect this.
* This was important in allowing us to write the xcbXorg connection
 code.
2025-01-14 14:17:05 -04:00
hayodea 4eb0ef75bc DevSpec: Yacc: Silence unused warning about yyunput() 2025-01-13 22:01:17 -04:00
hayodea 09caf314f1 Eliminate the C FFI; Namespace lib API and DeviceManager
We decided to get rid of the C FFI for libs. It was becoming too intricate
and complicated. It was becoming a technical burden and expanding into
too much extra code. It's unfortunate, but we'll have to give up on getting
out-of-tree hot-loadable libraries the easy way.

It's possible to still do it with cross compilation or by keeping track
of the libstdc++ version that the running harikoff binary was compiled
against. Then we can ensure that our loadable lib code is linked against
that same libstdc++ code and this should ensure ABI stability.
2025-01-13 21:57:11 -04:00
hayodea a4f96c8dfa Senselib FFI: Use devDesc object in SenseApiLib, also add per-device metadata to xcbXorg
We also had to write conversion constructors and so on to CSenseDeviceDesc.
The technical debt that's being piled up from this C FFI is excessive.
I think we'll end it here. API Libs will have to be written in C++
from now on. API Lib interfaces will be in C++.

We'll use cross compilers to ensure stability for out-of-tree lib
development.
2025-01-13 11:53:38 -04:00
hayodea 660f0f0e73 DevMgr: Make vectors hold sh_ptr and not uniq_ptr
This allows us to mirror the contents of the two lists into the unified
list much more easily.
2025-01-13 08:02:59 -04:00
hayodea edf51a4441 DevSpecp.yy: Fix mirror list use of std::move()d objects
We were building a list of mirrored items filled with the memory
pointed to by unique_ptrs which had already been std::move()d into
other unique_ptrs.
2025-01-13 07:06:28 -04:00
hayodea 8e94e829d0 SenseDevSpec: add NULL checks stringify, ostream::<< 2025-01-13 07:05:05 -04:00
hayodea 3f9b406fb2 Build: handle "" enableval in --enable-senseapi-xcbxorg 2025-01-12 14:36:27 -04:00
hayodea 0a36f7d370 Build: Add XCB_LIBS; Skeleton: mlo_initializeInd, mlo_attachDeviceReq
* Renamed some of the Sense API lib classes
  (CSensorDeviceDesc=>CSenseDeviceDesc,
  SensorDeviceDesc=>SenseDeviceDesc).
* Moved SenseApiDesc into /include/user/senseApiDesc.
* Add conversion constructor to convert from SenseDeviceDesc
  to
* Wireframe mlo_initializeInd to call xcb_connect().
* Add $(XCB_LIBS) to libxcbXorg_LDFLAGS.
* Wireframe mlo_attachDeviceReq().
2025-01-12 14:31:33 -04:00
hayodea b85d6f76a6 SenseApiMgr: add initialize/finalizeAllSenseApiLibs()
Also, SenseApiDesc: initializeInd() now takes void. We no longer
try to pass a struct of marionette-role ops into the libs. We'll
be using message queueing for the handshake side of async calls now.
2025-01-12 09:44:49 -04:00
hayodea c8a7a6678f Fix annoying build warning 2025-01-12 09:44:08 -04:00
hayodea c6577b1155 Add stringifiers to SenseApi related classes 2025-01-11 06:40:43 -04:00
hayodea 8aa28a877e Marionette: Post initializeHarikoff() as a lambda 2025-01-11 06:19:11 -04:00
hayodea bffc32519b ComponentThreads: now basics are working.
Next step is to get the unified event loops working generically
and then we can begin region-splitting up the data in harikoff.

We'll assign all the global resource managers to Marionette and
then assign the Mind components to the respective component threads.
2025-01-11 04:35:11 -04:00
hayodea 876526364b Build: Added -Wall,extra,-pedantic, fixed warnings and peeves. 2025-01-10 18:27:10 -04:00
hayodea ce2d47e6b9 Build: formatting: add m4 quotes 2025-01-10 17:41:17 -04:00
hayodea 870b8de249 Marionette: Introduce concept and add other 3 component threads
We introduce the 4 main component threads of execution for Harikoff:
* Marionette: This is the resident hijacking module that makes Harikoff
  instances non-persons, if configured to allow hijacking.
* Director: :)
* Canvas: :)
* Subconscious: DB, storage and recall.
2025-01-10 17:37:49 -04:00
hayodea 4a9d2cb546 xcbXorg: Update initializationIndFn func prototype 2025-01-10 17:36:39 -04:00
hayodea c696db9e45 Build: Require Boost.Asio to be v1.69.0+ 2025-01-10 17:35:22 -04:00
hayodea d2d5b8960f Build: PRefix project link with http:// 2025-01-09 18:34:58 -04:00
hayodea 49d03df73b Build: Add AX_BOOST_[BASE/ASIO].m4, check for BOOST_ASIO 2025-01-09 18:21:21 -04:00
hayodea 9e35748d9a Rename Csal_lmo=>Csal_mlo, and introduce a Csal_mho role
* Introduce the hk end of the management role for the senseApiLibs.
* Implement a basic set of operations and callbacks for this role.
2025-01-09 17:18:24 -04:00
hayodea 53583e5735 SenseApiLib, SenseApiDesc improvements, new Sense API Mgmt Lib Ops role
SenseApiDesc:
* Use a number count for num exported implexor APIs instead of
  NULL-terminated list.
* Add sanity checker functions for structs.

SenseApiLib:
* Invoke the new sanity checkers on new Lib objects.
* SenseApiDesc is now a member object instead of being
  pointed to.

SenseApiManager:
* loadSenseApiLib now calls the SenseApiDesc getter function.
* loadSenseApiLib now fills out the SenseApiLib class object.

New Sense API Mgmt Sub-API:

This sub-api (metalanguage, some might call it) is used to initialize
the lib's connection to the provider. After this call, the lib should
be ready to attach new devices to its provider on behalf of Hk.
2025-01-09 06:03:43 -04:00
hayodea 2a397ae064 Build: Check for libXCB when building XcbXorg sense API 2025-01-08 18:36:34 -04:00
hayodea 88df316013 build: Conditionally compile senseApis 2025-01-08 18:27:40 -04:00
hayodea 396bcefbf4 XcbXorg: Fill in correct placeholder implexor algo name 2025-01-08 18:00:07 -04:00
hayodea 62db724246 senseApiMgr: Fix formatting 2025-01-08 17:58:08 -04:00
hayodea bbbd6c36cd Release: Tagging v0.00.002:
* Loadable sense API libraries.
2025-01-08 17:34:33 -04:00
hayodea d14cef5328 Move senseApi libs into their own outer subdir 2025-01-08 17:28:21 -04:00
hayodea 988e84a545 Pretty up exception message 2025-01-08 15:09:18 -04:00
hayodea 4f2fbaa255 Fix NULL ptr use from dlerror() 2025-01-08 15:08:51 -04:00
hayodea 01ddb6d842 Only search in senseApiLibPath if it's actually set 2025-01-08 15:08:23 -04:00
hayodea 1178970728 cmd:opts: Now set OptionParser::argv0 to argv[0] 2025-01-08 15:07:42 -04:00
hayodea 090f0d3b02 senseApiMgr: new method: loadAllSenseApisFromOptions
This method dlopens() all senseApi libs that were referenced by
device specs.
2025-01-08 15:06:31 -04:00
hayodea 04db7bf76c Fix build warning about decltype(dlclose) 2025-01-08 15:05:56 -04:00
hayodea 2dc3083cdb whitespace 2025-01-08 13:47:16 -04:00
hayodea bffa2b837c Opts: Make singleton; senseApi: check senseApiLibPath, get senseApiDescFn pointer.
* OptionsParser now has a singleton.
* We now use the cmdline opt -p <senseApiLibPath>, and search for
  the specified library in:
  * senseApiLibPath, then CWD, then the place where our executable
    is running from, and then finally we let the hosting OS do
    its own search.
* We now call dlsym() on dlopen()'d libs to to get the senseApiDescFn
  pointer.
2025-01-08 13:43:44 -04:00
hayodea b40790ee4a Whitespace 2025-01-08 11:50:16 -04:00
hayodea c864bcfdd2 SenseApis: Define descriptors exported by libs 2025-01-08 11:49:28 -04:00
hayodea f5e3986644 DeviceSpec:parser: improve exception messages 2025-01-08 11:46:59 -04:00
hayodea 5a5e2fa25f Fix const_cast and rearrange logic in senseApi method 2025-01-08 07:56:10 -04:00
hayodea b9aa53822f Indentation 2025-01-08 07:27:48 -04:00
hayodea 376b29871b Change version to 0.00.001. 2025-01-08 06:35:34 -04:00
hayodea fe3f911db4 SenseApis: New senseApiManager and X11XcbApi
Still fleshing these out but ultimately senseApiMgr will manage
sense apis, and the X11XcbApi is where we'll connect to Xcb and
read the screen.
2025-01-08 06:26:36 -04:00
hayodea f594d29a2d DevMgr: Add sensorDevSpecs list and make intero/extro lists use unique_ptr 2025-01-08 06:23:34 -04:00
hayodea 6a494f7ff7 cmd:opts: New -a (sense-api shlibs) and -p (api shlib search dir) opts 2025-01-08 06:19:46 -04:00
hayodea 36acbdfc36 cmd:opts: Add senseApiPath in prep for new cmd opts 2025-01-08 00:32:07 -04:00
hayodea dd7a75d9b5 devSpec: Update preprocessor error message 2025-01-07 20:21:15 -04:00
36 changed files with 11300 additions and 123 deletions
+11 -1
View File
@@ -63,7 +63,17 @@
"typeinfo": "cpp",
"variant": "cpp",
"cstring": "cpp",
"cinttypes": "cpp"
"cinttypes": "cpp",
"any": "cpp",
"codecvt": "cpp",
"complex": "cpp",
"coroutine": "cpp",
"csignal": "cpp",
"list": "cpp",
"source_location": "cpp",
"future": "cpp",
"shared_mutex": "cpp",
"typeindex": "cpp"
},
"editor.rulers": [80, 120]
}
+4 -2
View File
@@ -1,7 +1,9 @@
SUBDIRS = hcore
SUBDIRS = hcore senseApis
ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
bin_PROGRAMS = harikoff
harikoff_SOURCES = main.cpp
harikoff_LDADD = hcore/libhcore.a hcore/deviceManager/libdeviceManager.a
harikoff_LDADD = hcore/libhcore.a hcore/deviceManager/libdeviceManager.a \
hcore/senseApis/libsenseApis.a
+28 -5
View File
@@ -1,7 +1,7 @@
AC_INIT([Harriman-Peikoff Project], [0.00.000],
AC_INIT([Harriman-Peikoff Project], [0.00.002],
[latentprion@gmail.com],
[harikoff],
[github.com/latentprion/harikoff])
[http://github.com/latentprion/harikoff])
AC_CONFIG_SRCDIR([hcore/mind.cpp])
AC_CONFIG_AUX_DIR([autotools-aux])
@@ -31,28 +31,49 @@ AC_DEFINE_UNQUOTED([CONFIG_MIND_VOSCILLATOR_FREQ_MS],
[${MIND_VOSCILLATOR_FREQ_MS}],
[Frequency of the mind virtual oscillator in milliseconds])
m4_include([m4/ax_boost_base.m4])
m4_include([m4/ax_boost_asio_1.69.0.m4])
m4_include([m4/ac_prog_flex.m4])
m4_include([m4/ac_prog_bison.m4])
AC_PROG_CC
AC_PROG_CXX
AC_PROG_RANLIB
AM_PROG_AR
AC_PROG_LEX(noyywrap)
LT_INIT([shared])
AC_PROG_LEX([noyywrap])
AC_PROG_YACC
AS_IF([test -z "${LEX}" || test -z "${YACC}"], [
AC_MSG_ERROR([LEX and YACC must both be available in PATH.])
])
AX_BOOST_BASE([1.69.0], [], [AC_MSG_ERROR(m4_normalize([Boost v1.69.0 or higher
is required, because Boost.System is header-only from 1.69.0 onwards.]))])
AX_BOOST_ASIO_gte_1_69_0
AS_IF([test "x${HAVE_BOOST_ASIO}" == "x"], [
AC_MSG_ERROR(m4_normalize([Boost.Asio must be available in headers.
Try --with-boost-asio if need be.]))
])
AM_CPPFLAGS=m4_normalize(["-I\"\$(top_srcdir)/include\""])
AC_SEARCH_LIBS([dlopen], [dl ldl], [], [
AC_MSG_ERROR([dlopen() not found in libdl or libldl.])])
AC_SEARCH_LIBS([dlsym], [dl ldl], [], [
AC_MSG_ERROR([dlsym() not found in libdl or libldl.])])
AM_CPPFLAGS=m4_normalize(["-I\"\$(top_srcdir)/include\"
-Wall -Wextra -pedantic"])
AC_SUBST([AM_CPPFLAGS])
AC_SUBST([YACC])
AC_SUBST([LEX])
m4_include([m4/sense_api_opts.m4])
AC_SUBST([SENSEAPIS_ENABLED])
AC_CONFIG_HEADERS([include/config.h])
AC_CONFIG_FILES([
Makefile hcore/Makefile
hcore/deviceManager/Makefile
hcore/senseApis/Makefile
senseApis/Makefile
senseApis/xcbXorg/Makefile
])
AC_CONFIG_COMMANDS_POST([
@@ -60,6 +81,8 @@ AC_CONFIG_COMMANDS_POST([
AC_MSG_NOTICE(m4_normalize([* MIND_VOSCILLATOR_PERIOD_MS:
${MIND_VOSCILLATOR_PERIOD_MS} ms
(freq: ${MIND_VOSCILLATOR_FREQ_MS} Hz)]))
AC_MSG_NOTICE(m4_normalize(
[* SenseAPI backends enabled: ${SENSEAPIS_ENABLED}]))
])
AC_OUTPUT
-5
View File
@@ -1,5 +0,0 @@
# DeviceSpec: API `x11`, server `xorg`:
* `xwininfo` is relevant.
+121
View File
@@ -0,0 +1,121 @@
# DeviceSpec: API `xcb`, provider `xorg`
## Overview
The `xcb` API with the `xorg` provider allows Harikoff to interact with Xorg
server windows. This can be used to capture visual data from specific windows
or entire screens managed by the Xorg server.
## DeviceSpec Format
The general format of a device-spec for the `xcb` API with the `xorg` provider
is:
```
sensor-type|implexor|xcb(api-params)|xorg(provider-params)|deviceSelector
```
* `sensor-type` is always either '`+idev`' (interoceptor), '`+edev`'
(extrospector), or '`+adev`' (actuator).
* `implexor` is the name of the implexor algorithm that should be used with
the data that is provided by the `provider` via the `api`.
* `api` is `xcb` in this case, and the `api-params` in parentheses may be
omitted, in which case the parentheses will be empty, but the parentheses
must always be written out.
* `provider` is `xorg` in this case, and the `provider-params` in parentheses
may be omitted, in which case the parentheses will be empty, but the
parentheses must always be written out.
* `deviceSelector` is the idiosyncratic label/name used by the `provider` to
identify the specific window or screen you want to access via that
`provider`.
## `api-params` and `provider-params`
### `api-params`
The `api-params` for the `xcb` API can include the following:
* `dev-id` or `devid`: Specifies that the `deviceSelector` is a numeric window
ID. The ID can be specified in decimal or hexadecimal format.
* `dev-string`, `dev-str`, `devstr`, or `devstring`: Specifies that the
`deviceSelector` is an exact window name.
* `dev-substring`, `dev-substr`, `devsubstr`, or `devsubstring`: Specifies
that the `deviceSelector` is a substring match (default).
Example:
```
xcb(dev-id)|123456
xcb(dev-id)|0x1e240
xcb(dev-string)|exact-window-name
xcb(dev-substring)|window-name
```
### `provider-params`
The `provider-params` for the `xorg` provider can include the following:
* `display`: The display number (e.g., `0` for `:0`).
* `screen`: The screen number within the display (e.g., `0` for the first
screen).
Example:
```
xorg(display=0|screen=0)
```
## `deviceSelector`
The `deviceSelector` can be one of the following:
* A numeric window ID.
* A window name (exact match or substring match).
### Matching Types
* By default, the `deviceSelector` is treated as a substring match.
* To specify an exact match, use the `dev-string` parameter.
* To specify a numeric window ID, use the `dev-id` parameter.
Example:
```
xcb(dev-substring)|window-name
xcb(dev-string)|exact-window-name
xcb(dev-id)|123456
```
## Escaping Whitespace
In `deviceSelector` and other string tokens, whitespace can be included by
prefixing it with a backslash (`\`). The backslash will be discarded during
parsing.
Example:
```
xcb(dev-string)|My\ Exact\ Window\ Name
```
## Examples
### To attach a specific window by name (substring match):
```
+edev|visual-implexor|xcb(dev-substring)|xorg(display=0|screen=0)|my-window
```
This will attach to a window whose name contains "my-window" as a substring.
### To attach a specific window by exact name:
```
+edev|visual-implexor|xcb(dev-string)|xorg(display=0|screen=0)|My\ Exact\ Window\ Name
```
This will attach to a window whose name exactly matches "My Exact Window Name".
### To attach a specific window by numeric ID:
```
+edev|visual-implexor|xcb(dev-id)|xorg(display=0|screen=0)|123456
```
This will attach to a window with the numeric ID `123456`.
### To attach the entire screen:
```
+edev|visual-implexor|xcb()|xorg(display=0|screen=0)|all
```
This will attach to the entire screen `0` of display `0`.
+5
View File
@@ -46,6 +46,11 @@ If there's more than one parameter item in a list of `api-params` or
+edev|audio-implexor|alsa(shmem|param2|param3)|alsa()|cardname
```
Each parameter must be in one of these forms:
* key=value
* key=
* key
Some examples follow:
### To attach a particular window from a window manager:
+3 -2
View File
@@ -1,5 +1,6 @@
SUBDIRS = deviceManager
SUBDIRS = deviceManager senseApis
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
noinst_LIBRARIES = libhcore.a
libhcore_a_SOURCES = mind.cpp opts.cpp
libhcore_a_SOURCES = mind.cpp opts.cpp componentThread.cpp
+69
View File
@@ -0,0 +1,69 @@
#include <iostream>
#include <componentThread.h>
namespace hk {
namespace director {
ComponentThread director;
}
namespace simulator {
ComponentThread canvas;
}
namespace subconscious {
ComponentThread subconscious;
}
std::unordered_map<std::thread::id, ComponentThread&>
ComponentThread::componentThreads =
{
{director::director.thread.get_id(), director::director},
{simulator::canvas.thread.get_id(), simulator::canvas},
{subconscious::subconscious.thread.get_id(), subconscious::subconscious}
};
void ComponentThread::signalThread(std::thread::id id)
{
auto it = componentThreads.find(id);
if (it == componentThreads.end())
{
throw std::runtime_error(std::string(__func__)
+ ": Thread ID not found in componentThreads map");
}
ComponentThread& componentThread = it->second;
{
std::lock_guard<std::mutex> lock(componentThread.startupSync.mutex);
componentThread.startupSync.ready = true;
}
componentThread.startupSync.cv.notify_one();
}
void ComponentThread::main(ComponentThread& self)
{
// We sleep on spawn until the main thread tells us to continue.
{
std::unique_lock<std::mutex> lock(self.startupSync.mutex);
self.startupSync.cv.wait(lock, [&self]() {
return self.startupSync.ready;
});
}
std::cout << __func__ << ": Starting event loop." << std::endl;
self.getIoService().run();
std::cout << __func__ << ": Exiting." << std::endl;
}
void ComponentThread::validateThreadIds(void)
{
for (const auto& [id, componentThread] : componentThreads)
{
// std::thread::id() is usable as an invalid ID.
if (id == std::thread::id())
{
throw std::runtime_error(
std::string(__func__) + ": Invalid Thread ID.");
}
}
}
} // namespace hk
+13 -22
View File
@@ -4,43 +4,34 @@
#include <string>
#include <vector>
#include <sstream>
#include <memory>
#include <opts.h>
#include <deviceManager/deviceManager.h>
namespace hk {
namespace device {
std::vector<DeviceManager::InteroceptorDeviceSpec>
std::vector<std::shared_ptr<InteroceptorDeviceSpec>>
DeviceManager::interoceptorDeviceSpecs;
std::vector<DeviceManager::ExtrospectorDeviceSpec>
std::vector<std::shared_ptr<ExtrospectorDeviceSpec>>
DeviceManager::extrospectorDeviceSpecs;
std::vector<std::shared_ptr<SenseDeviceSpec>>
DeviceManager::senseDeviceSpecs;
std::ostream& operator<<(
std::ostream& os, const DeviceManager::SensorDeviceSpec& spec)
{
os << "Device: " << spec.sensorType << ", Implexor: "
<< spec.implexor << ", API: " << spec.api
<< ", API Params: (";
for (auto it = spec.apiParams.begin(); it != spec.apiParams.end(); ++it) {
os << *it << (it + 1 == spec.apiParams.end() ? "" : " ");
}
os << "), Provider: " << spec.provider << ", Provider Params: (";
for (auto it = spec.providerParams.begin(); it != spec.providerParams.end(); ++it) {
os << *it << (it + 1 == spec.providerParams.end() ? "" : " ");
}
os << "), Device Selector: " << spec.deviceSelector << std::endl;
return os;
}
const std::string DeviceManager::printDeviceSpecs(void)
const std::string DeviceManager::stringifyDeviceSpecs(void)
{
std::ostringstream oss;
for (const auto& spec : DeviceManager::interoceptorDeviceSpecs) {
oss << "Interoceptor " << spec;
oss << "Interoceptor " << spec->stringify();
}
for (const auto& spec : DeviceManager::extrospectorDeviceSpecs) {
oss << "Extrospector " << spec;
oss << "Extrospector " << spec->stringify();
}
return oss.str();
}
} // namespace device
} // namespace hk
+18 -5
View File
@@ -10,22 +10,28 @@
#include "deviceSpecp.hh"
#include "deviceSpecl.hh"
namespace hk {
namespace device {
std::string DeviceManager::readDeviceFile(const std::string& filename)
{
std::ifstream file(filename);
if (!file.is_open()) {
throw std::runtime_error("Could not open file: " + filename);
throw std::runtime_error(
std::string(__func__) + ": Couldn't open deviceSpec file: "
+ filename);
}
std::string content(
(std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
return std::move(content);
return content;
}
void DeviceManager::collateAllDeviceSpecs(const OptionParser& options)
void DeviceManager::collateAllDeviceSpecs(void)
{
OptionParser &options = OptionParser::getOptions();
allDeviceSpecs = options.deviceSpecs;
for (const auto& file : options.deviceSpecFiles)
@@ -46,11 +52,18 @@ void DeviceManager::parseAllDeviceSpecs(void)
&fclose);
if (!input) {
throw std::runtime_error("Failed to open memory as file");
throw std::runtime_error(
std::string(__func__) + ": Failed to fmemopen() a FILE* for "
"parsing device specs");
}
deviceSpeclin = input.get();
if (deviceSpecpparse()) {
throw std::runtime_error("Failed to parse device specs");
throw std::runtime_error(
std::string(__func__) + ": Failed to parse device specs. "
"Check specs for errors");
}
}
} // namespace device
} // namespace hk
+10 -1
View File
@@ -1,6 +1,9 @@
%option prefix="deviceSpecl"
%option nounput
%{
#include <vector>
#include <string>
#include <algorithm>
#include <deviceManager/deviceManager.h>
#include "deviceSpecp.hh"
%}
@@ -22,7 +25,13 @@
"|" { return PIPE; }
"(" { return LPAREN; }
")" { return RPAREN; }
[^\|\(\) \t\r\n]+ { deviceSpecplval.str = strdup(yytext); return STRING; }
[ \t]*"="[ \t]* { return EQUALS; } // Allow optional whitespace around equals
([^=\|\(\) \t\r\n]|\\[ \t])+ {
std::string token(yytext);
token.erase(std::remove(token.begin(), token.end(), '\\'), token.end());
deviceSpecplval.str = strdup(token.c_str());
return STRING;
}
\r?\n { /* ignore newlines */ }
[ \t]+ { /* ignore whitespace */ }
. { return yytext[0]; }
+57 -20
View File
@@ -5,6 +5,9 @@
#include <cstring>
#include <cstdlib>
#include <stdexcept>
#include <memory>
#include <functional>
#include <user/senseDeviceSpec.h>
#include <deviceManager/deviceManager.h>
#ifndef yylex
@@ -17,18 +20,25 @@
* lexer must have the same prefix as the parser they generate. So we just use
* this #define below to override yacc/bison's presumed prefix for the lexer.
*/
#error "Yacc should have defined yylex, and we need to override it to tell yacc the name of our lex function."
#error "Yacc should have defined yylex as a preprocessor token, and we need to override it to tell yacc the name of our lex function."
#endif
#undef yylex
#define yylex deviceSpecllex
#ifdef yytext
#undef yytext
#endif
#define yytext deviceSpecltext
// Declare the symbols that our lexer will export.
int yylex(void);
extern char* yytext; // Declare yytext to access the current token text
void yyerror(const char *message)
{
throw std::runtime_error(
throw std::runtime_error(
std::string("deviceSpec parser error: ")
+ std::string(message));
+ std::string(message)
+ " at token: " + std::string(yytext));
}
%}
@@ -36,18 +46,21 @@ void yyerror(const char *message)
%union {
char* str;
char chr;
DeviceManager::SensorDeviceSpec* sensorSpec;
DeviceManager::InteroceptorDeviceSpec* interoceptorSpec;
DeviceManager::ExtrospectorDeviceSpec* extrospectorSpec;
std::vector<std::string>* stringVector;
hk::device::SenseDeviceSpec* sensorSpec;
hk::device::InteroceptorDeviceSpec* interoceptorSpec;
hk::device::ExtrospectorDeviceSpec* extrospectorSpec;
std::vector<std::pair<std::string,std::string>>* paramVector;
std::pair<std::string,std::string>* param;
}
%token <str> STRING
%token PIPE DOUBLE_PIPE LPAREN RPAREN
%token <chr> KEYWORD_SPECTYPE_ACTUATOR
%token <chr> KEYWORD_SPECTYPE_EXTROSPECTOR KEYWORD_SPECTYPE_INTEROSPECTOR
%token EQUALS // Add new token for '='
%type <stringVector> params opt_params
%type <paramVector> params opt_params
%type <param> param
%type <sensorSpec> spec_body
%type <interoceptorSpec> interoceptor_spec
%type <extrospectorSpec> extrospector_spec
@@ -70,29 +83,33 @@ sensor_spec:
interoceptor_spec:
KEYWORD_SPECTYPE_INTEROSPECTOR PIPE spec_body {
DeviceManager::InteroceptorDeviceSpec *spec =
static_cast<DeviceManager::InteroceptorDeviceSpec *>($3);
auto spec = std::make_shared<hk::device::InteroceptorDeviceSpec>(
*static_cast<hk::device::InteroceptorDeviceSpec *>($3));
spec->sensorType = $1;
DeviceManager::interoceptorDeviceSpecs.push_back(*spec);
delete spec;
hk::device::DeviceManager::interoceptorDeviceSpecs.push_back(spec);
hk::device::DeviceManager::senseDeviceSpecs.push_back(spec);
delete $3;
}
;
extrospector_spec:
KEYWORD_SPECTYPE_EXTROSPECTOR PIPE spec_body {
DeviceManager::ExtrospectorDeviceSpec *spec =
static_cast<DeviceManager::ExtrospectorDeviceSpec *>($3);
auto spec = std::make_shared<hk::device::ExtrospectorDeviceSpec>(
*static_cast<hk::device::ExtrospectorDeviceSpec *>($3));
spec->sensorType = $1;
DeviceManager::extrospectorDeviceSpecs.push_back(*spec);
delete spec;
hk::device::DeviceManager::extrospectorDeviceSpecs.push_back(spec);
hk::device::DeviceManager::senseDeviceSpecs.push_back(spec);
delete $3;
}
;
spec_body:
STRING PIPE STRING LPAREN opt_params RPAREN PIPE STRING LPAREN opt_params RPAREN PIPE STRING {
$$ = new DeviceManager::SensorDeviceSpec();
$$ = new hk::device::SenseDeviceSpec();
$$->sensorType = '\0';
$$->implexor = std::string($1);
$$->api = std::string($3);
@@ -107,12 +124,32 @@ spec_body:
opt_params:
params
| /* empty */ { $$ = new std::vector<std::string>(); }
| /* empty */ { $$ = new std::vector<std::pair<std::string,std::string>>(); }
;
params:
STRING { $$ = new std::vector<std::string>{ $1 }; }
| params PIPE STRING { $$ = $1; $$->push_back($3); }
param {
$$ = new std::vector<std::pair<std::string,std::string>>();
$$->push_back(*$1);
delete $1;
}
| params PIPE param {
$$ = $1;
$$->push_back(*$3);
delete $3;
}
;
param:
STRING {
$$ = new std::pair<std::string,std::string>($1, "");
}
| STRING EQUALS {
$$ = new std::pair<std::string,std::string>($1, "");
}
| STRING EQUALS STRING {
$$ = new std::pair<std::string,std::string>($1, $3);
}
;
%%
+69
View File
@@ -0,0 +1,69 @@
#ifndef COMPONENT_THREAD_H
#define COMPONENT_THREAD_H
#include <thread>
#include <unordered_map>
#include <condition_variable>
#include <boost/asio.hpp>
#include <stdexcept>
namespace hk {
class ComponentThread
{
public:
ComponentThread()
: work(io_service), startupSync(),
thread(ComponentThread::main, std::ref(*this))
{}
boost::asio::io_service& getIoService(void) { return io_service; }
static boost::asio::io_service& getEventLoop(
std::thread::id id = std::this_thread::get_id())
{
auto it = componentThreads.find(id);
if (it == componentThreads.end())
{
throw std::runtime_error(std::string(__func__)
+ ": Thread ID not found in componentThreads map");
}
return it->second.getIoService();
}
static void main(ComponentThread &self);
static void signalThread(std::thread::id id);
static void validateThreadIds(void);
public:
boost::asio::io_service io_service;
boost::asio::io_service::work work;
struct StartupSync {
std::mutex mutex;
std::condition_variable cv;
bool ready;
StartupSync() : ready(false) {}
} startupSync;
/* Always ensure that this is last so that the thread is spawned after
* everything else.
*/
std::thread thread;
static std::unordered_map<std::thread::id, ComponentThread&> componentThreads;
};
namespace director {
extern ComponentThread director;
}
namespace simulator {
extern ComponentThread canvas;
}
namespace subconscious {
extern ComponentThread subconscious;
}
} // namespace hk
#endif // COMPONENT_THREAD_H
+16 -26
View File
@@ -3,35 +3,18 @@
#include <vector>
#include <string>
#include <memory>
#include <opts.h>
#include <utility>
#include <iostream>
#include <user/senseDeviceSpec.h>
namespace hk {
namespace device {
class DeviceManager
{
public:
struct SensorDeviceSpec
{
char sensorType;
std::string implexor;
std::string api;
std::vector<std::string> apiParams;
std::string provider;
std::vector<std::string> providerParams;
std::string deviceSelector;
friend std::ostream& operator<<(
std::ostream& os, const SensorDeviceSpec& spec);
};
struct InteroceptorDeviceSpec : public SensorDeviceSpec
{
};
struct ExtrospectorDeviceSpec : public SensorDeviceSpec
{
};
static DeviceManager& getInstance()
{
static DeviceManager instance;
@@ -39,9 +22,9 @@ public:
}
std::string readDeviceFile(const std::string& filename);
void collateAllDeviceSpecs(const OptionParser& options);
void collateAllDeviceSpecs(void);
void parseAllDeviceSpecs(void);
static const std::string printDeviceSpecs();
static const std::string stringifyDeviceSpecs(void);
private:
DeviceManager() = default;
@@ -51,8 +34,15 @@ private:
public:
std::string allDeviceSpecs;
static std::vector<InteroceptorDeviceSpec> interoceptorDeviceSpecs;
static std::vector<ExtrospectorDeviceSpec> extrospectorDeviceSpecs;
static std::vector<std::shared_ptr<InteroceptorDeviceSpec>>
interoceptorDeviceSpecs;
static std::vector<std::shared_ptr<ExtrospectorDeviceSpec>>
extrospectorDeviceSpecs;
static std::vector<std::shared_ptr<SenseDeviceSpec>>
senseDeviceSpecs;
};
} // namespace device
} // namespace hk
#endif // DEVICEMANAGER_H
+11 -2
View File
@@ -12,11 +12,20 @@ public:
OptionParser() : verbose(false), printUsage(false) {}
~OptionParser() = default;
void parseArguments(int argc, char *argv[]);
void dumpOptions() const;
void parseArguments(int argc, char *argv[], char **envp);
std::string stringifyOptions(void) const;
std::string getUsage() const;
static OptionParser &getOptions(void)
{
static OptionParser options;
return options;
}
public:
std::string argv0;
std::string senseApiLibPath;
std::vector<std::string> senseApiLibs;
std::string deviceSpecs;
std::vector<std::string> deviceSpecFiles;
bool verbose, printUsage;
+83
View File
@@ -0,0 +1,83 @@
#ifndef SENSE_API_PROVIDER_DESC_H
#define SENSE_API_PROVIDER_DESC_H
#include <string>
#include <memory>
#include <vector>
#include <dlfcn.h>
#include <functional>
#include <user/senseApiDesc.h>
namespace hk {
namespace sense_api {
class SenseApiLib
{
private:
friend class SenseApiManager;
struct DlCloser
{
void operator()(void* handle) const
{
if (handle) {
dlclose(handle);
}
}
};
public:
SenseApiLib(
const std::string& path, void *_dlopen_handle, getSenseApiDescFn *descFn)
: libraryPath(path),
dlopen_handle(_dlopen_handle, DlCloser()),
HK_GET_SENSE_API_DESC_FN_NAME(descFn)
{}
void setSenseApiDesc(const SenseApiDesc &desc)
{
if (!SenseApiDesc::sanityCheck(desc))
{
throw std::runtime_error(
std::string(__func__) + ": Sanity check failed for sense API "
"descriptor in library '" + libraryPath + "'");
}
senseApiDesc = desc;
}
public:
std::string libraryPath;
std::unique_ptr<void, DlCloser> dlopen_handle;
/* UNIMPLEMENTED: API-specific cmdline options. These affect this specific
* sense api lib's behaviour globally.
*/
std::vector<std::string> options;
/**
* @brief Every sense API lib is required to provide a function that returns
* a SenseApiDesc struct. This struct states which API the lib uses to
* connect Harikoff to the sense provider it supports.
*
* This getter function should be visible to dlsym() so that Harikoff can
* find it in the lib after loading it, and call it.
*/
std::function<getSenseApiDescFn> HK_GET_SENSE_API_DESC_FN_NAME;
/**
* @brief Harikoff will call the `HK_GET_SENSE_API_DESC_FN_NAME` getter
* function and use the data it provides in order to fill out this
* descriptor.
*/
SenseApiDesc senseApiDesc;
std::string stringify() const {
std::string result = "Library Path: " + libraryPath + "\n";
result += "Sense API Descriptor: " + senseApiDesc.stringify() + "\n";
return result;
}
};
} // namespace sense_api
} // namespace hk
#endif // SENSE_API_PROVIDER_DESC_H
+60
View File
@@ -0,0 +1,60 @@
#ifndef SENSE_API_MANAGER_H
#define SENSE_API_MANAGER_H
#include <config.h>
#include <memory>
#include <vector>
#include <string>
#include <optional>
#include <functional>
#include <senseApis/senseApiLib.h>
#include <user/senseDeviceSpec.h>
namespace hk {
namespace sense_api {
class SenseApiManager
{
public:
static SenseApiManager& getInstance()
{
static SenseApiManager instance;
return instance;
}
SenseApiLib& loadSenseApiLib(const std::string& libraryPath);
std::optional<std::reference_wrapper<SenseApiLib>> getSenseApiLib(
const std::string& libraryPath);
std::optional<std::reference_wrapper<SenseApiLib>> getSenseApiLibByApiName(
const std::string& apiName);
void unloadSenseApiLib(const std::string& libraryPath);
void initializeSenseApiLib(SenseApiLib& lib);
void finalizeSenseApiLib(SenseApiLib& lib);
void loadAllSenseApiLibsFromOptions(void);
void unloadAllSenseApiLibs(void);
void initializeAllSenseApiLibs(void);
void finalizeAllSenseApiLibs(void);
void attachAllSenseDevicesFromSpecs(void);
void attachSenseDevice(const device::SenseDeviceSpec& spec);
void detachSenseDevice(const device::SenseDeviceSpec& spec);
void detachAllSenseDevices(void);
std::string stringifyLibs() const;
private:
SenseApiManager() = default;
~SenseApiManager() = default;
SenseApiManager(const SenseApiManager&) = delete;
SenseApiManager& operator=(const SenseApiManager&) = delete;
std::vector<std::unique_ptr<SenseApiLib>> senseApiLibs;
};
} // namespace sense_api
} // namespace hk
#endif // SENSE_API_MANAGER_H
+59 -10
View File
@@ -4,6 +4,9 @@
#include <getopt.h>
#include <string>
#include <vector>
#include <sys/stat.h>
#include <sstream>
struct option OptionParser::longOptions[] = {
{"devicespec", required_argument, 0, 's'},
@@ -11,18 +14,25 @@ struct option OptionParser::longOptions[] = {
{"devspec", required_argument, 0, 's'},
{"devfile", required_argument, 0, 'd'},
{"devicefile", required_argument, 0, 'd'},
{"sense-api-lib", required_argument, 0, 'a'},
{"senseapi", required_argument, 0, 'a'},
{"sense-api-path", required_argument, 0, 'p'},
{"verbose", no_argument, 0, 'v'},
{"help", no_argument, 0, '?'},
{0, 0, 0, 0}
};
void OptionParser::parseArguments(int argc, char *argv[])
void OptionParser::parseArguments(int argc, char *argv[], char **envp)
{
(void)envp;
int opt;
int optionIndex = 0;
argv0 = argv[0];
optind = 1; // Reset optind to 1 before parsing
while ((opt = getopt_long(
argc, argv, "s:d:v?", longOptions, &optionIndex)) != -1)
argc, argv, "s:d:a:p:v?", longOptions, &optionIndex)) != -1)
{
switch (opt)
{
@@ -35,6 +45,30 @@ void OptionParser::parseArguments(int argc, char *argv[])
case 'd':
deviceSpecFiles.push_back(optarg);
break;
case 'a':
senseApiLibs.push_back(optarg);
break;
case 'p':
{
struct stat info;
if (!senseApiLibPath.empty())
{
std::cerr << std::string(__func__)
+ " - Overwriting previous sense-api-path with: " << optarg
<< '\n';
}
if (stat(optarg, &info) != 0 || !(info.st_mode & S_IFDIR))
{
throw std::invalid_argument(
std::string(__func__) + " - The specified path is not a "
"directory: " + optarg);
}
senseApiLibPath = optarg;
break;
}
case 'v':
verbose = true;
break;
@@ -42,30 +76,45 @@ void OptionParser::parseArguments(int argc, char *argv[])
printUsage = true;
return;
default:
throw std::invalid_argument("Invalid argument encountered: " + std::string(argv[optind - 1]));
throw std::invalid_argument(
std::string(__func__) + " - Invalid argument encountered: "
+ std::string(argv[optind - 1]));
}
}
}
std::string OptionParser::getUsage() const
{
return "Usage: program [-s|--devicespec|--spec|--devspec <device_spec>] "
return "Usage: " + argv0 + " [-s|--devicespec|--spec|--devspec <device_spec>] "
"[-d|--devfile|--devicefile <filename>] "
"[-a|--sense-api-lib|--senseapi <filename>] "
"[-p|--sense-api-path <directory>] "
"[-v|--verbose] "
"[-?|--help]";
}
void OptionParser::dumpOptions() const
std::string OptionParser::stringifyOptions(void) const
{
std::ostringstream oss;
if (verbose) {
std::cout << "Verbose mode is on" << std::endl;
oss << "Verbose mode is on" << std::endl;
}
std::cout << "Device Specs: " << deviceSpecs << std::endl;
oss << "Device Specs: " << deviceSpecs << std::endl;
std::cout << "Device Spec Files: ";
oss << "Device Spec Files: ";
for (const auto& file : deviceSpecFiles) {
std::cout << file << " ";
oss << file << " ";
}
std::cout << std::endl;
oss << std::endl;
oss << "Sense API Library Path: " << senseApiLibPath << std::endl;
oss << "Sense API Libraries: ";
for (const auto& lib : senseApiLibs) {
oss << lib << " ";
}
oss << std::endl;
return oss.str();
}
+4
View File
@@ -0,0 +1,4 @@
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
noinst_LIBRARIES=libsenseApis.a
libsenseApis_a_SOURCES=senseApiManager.cpp
+268
View File
@@ -0,0 +1,268 @@
#include <iostream>
#include <stdexcept>
#include <optional>
#include <filesystem>
#include <senseApis/senseApiManager.h>
#include <senseApis/senseApiLib.h>
#include <opts.h>
#include <user/senseApiDesc.h>
#include <deviceManager/deviceManager.h>
namespace fs = std::filesystem;
namespace hk {
namespace sense_api {
/**
* @brief Searches for a library in predefined locations
* @param libraryPath The name or path of the library to find
* @return Optional containing the full path if found in search paths, nullopt
* if not
*
* Searches for the library in the following locations in order:
* 1. Custom path specified by --sense-api-lib-path option (if provided)
* 2. Current working directory
* 3. Directory containing the executable
*
* If the library is not found in any of these locations, returns nullopt and
* falls back to system default library search paths (LD_LIBRARY_PATH, etc.)
*/
static std::optional<std::string> findLibraryPath(
const std::string& libraryPath)
{
std::vector<std::string> searchPaths = {
fs::current_path().string(),
fs::path("/proc/self/exe").parent_path().string()
};
if (!OptionParser::getOptions().senseApiLibPath.empty())
{
searchPaths.insert(
searchPaths.begin(), OptionParser::getOptions().senseApiLibPath);
}
for (const auto& path : searchPaths)
{
fs::path fullPath = fs::path(path) / libraryPath;
if (fs::exists(fullPath))
{
return fullPath.string();
}
}
std::cerr << std::string(__func__) + ": library '"
+ libraryPath + "' isn't in search bespoke search paths: ";
for (const auto& path : searchPaths) {
std::cerr << path << " ";
}
std::cerr << std::endl;
std::cerr << "Trying to load " + libraryPath + " from system default "
"search paths\n";
return std::nullopt;
}
SenseApiLib& SenseApiManager::loadSenseApiLib(const std::string& libraryPath)
{
std::optional<std::string> fullPath = findLibraryPath(libraryPath);
std::string resolvedPath = fullPath.value_or(libraryPath);
// Clear any existing error
dlerror();
auto dlopen_handle = std::unique_ptr<void, SenseApiLib::DlCloser>(
dlopen(resolvedPath.c_str(), RTLD_LAZY));
if (!dlopen_handle && fullPath.has_value())
{
// Fallback to using the supplied libraryPath
dlerror();
dlopen_handle.reset(dlopen(libraryPath.c_str(), RTLD_LAZY));
}
if (!dlopen_handle)
{
const char *dlerr = dlerror();
std::string error = (dlerr
? dlerr
: "Unknown error while opening shlib");
throw std::runtime_error(
std::string(__func__) + ": Cannot load library '"
+ libraryPath + "': "
+ error);
}
// Initialize getSenseApiDescriptor
auto func = reinterpret_cast<getSenseApiDescFn *>(
dlsym(dlopen_handle.get(), HK_GET_SENSE_API_DESC_FN_NAME_STR));
if (!func)
{
throw std::runtime_error(
std::string(__func__) + ": dlsym('"
HK_GET_SENSE_API_DESC_FN_NAME_STR "') failed for library '"
+ libraryPath + "'");
}
const SenseApiDesc &libApiDesc = func();
auto lib = std::make_unique<SenseApiLib>(
libraryPath, dlopen_handle.release(), func);
lib->setSenseApiDesc(libApiDesc);
senseApiLibs.push_back(std::move(lib));
return *senseApiLibs.back();
}
std::optional<std::reference_wrapper<SenseApiLib>>
SenseApiManager::getSenseApiLib(const std::string& libraryPath)
{
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
[&libPath = libraryPath](const std::unique_ptr<SenseApiLib>& lib) {
return lib->libraryPath == libPath;
}
);
if (it != senseApiLibs.end()) { return **it; }
return std::nullopt;
}
std::optional<std::reference_wrapper<SenseApiLib>>
SenseApiManager::getSenseApiLibByApiName(const std::string& apiName)
{
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
[&apiName](const std::unique_ptr<SenseApiLib>& lib) {
return lib->senseApiDesc.name == apiName;
}
);
if (it != senseApiLibs.end()) { return **it; }
return std::nullopt;
}
void SenseApiManager::unloadSenseApiLib(const std::string& libraryPath)
{
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
[&lpath = libraryPath](const std::unique_ptr<SenseApiLib>& lib) {
return lib->libraryPath == lpath;
}
);
if (it != senseApiLibs.end())
{
senseApiLibs.erase(it);
return;
}
std::cerr << std::string(__func__) + ": Library not found: "
<< libraryPath << '\n';
}
void SenseApiManager::unloadAllSenseApiLibs(void)
{
senseApiLibs.clear();
}
void SenseApiManager::loadAllSenseApiLibsFromOptions()
{
const auto& options = OptionParser::getOptions();
for (const auto& libPath : options.senseApiLibs) {
loadSenseApiLib(libPath);
}
}
std::string SenseApiManager::stringifyLibs() const
{
std::string result;
for (const auto& lib : senseApiLibs) {
result += lib->stringify() + "\n";
}
return result;
}
void SenseApiManager::initializeSenseApiLib(SenseApiLib& lib)
{
if (!lib.senseApiDesc.sal_mgmt_libOps.initializeInd)
{
throw std::runtime_error(
std::string(__func__) + ": initializeInd() is NULL for library '"
+ lib.libraryPath + "'");
}
lib.senseApiDesc.sal_mgmt_libOps.initializeInd();
}
void SenseApiManager::finalizeSenseApiLib(SenseApiLib& lib)
{
if (!lib.senseApiDesc.sal_mgmt_libOps.finalizeInd)
{
throw std::runtime_error(
std::string(__func__) + ": finalizeInd() is NULL for library '"
+ lib.libraryPath + "'");
}
lib.senseApiDesc.sal_mgmt_libOps.finalizeInd();
}
void SenseApiManager::initializeAllSenseApiLibs(void)
{
for (auto& lib : senseApiLibs) {
initializeSenseApiLib(*lib);
}
}
void SenseApiManager::finalizeAllSenseApiLibs(void)
{
for (auto& lib : senseApiLibs) {
finalizeSenseApiLib(*lib);
}
}
void SenseApiManager::attachSenseDevice(const device::SenseDeviceSpec& spec)
{
auto libOpt = getSenseApiLibByApiName(spec.api);
if (!libOpt)
{
throw std::runtime_error(
std::string(__func__) + ": No library found for API '"
+ spec.api + "'");
}
auto& lib = libOpt.value().get();
if (!lib.senseApiDesc.sal_mgmt_libOps.attachDeviceReq)
{
throw std::runtime_error(
std::string(__func__) + ": attachDeviceReq() is NULL for library '"
+ lib.libraryPath + "'");
}
lib.senseApiDesc.sal_mgmt_libOps.attachDeviceReq(spec);
}
void SenseApiManager::detachSenseDevice(const device::SenseDeviceSpec& spec)
{
auto libOpt = getSenseApiLibByApiName(spec.api);
if (!libOpt)
{
throw std::runtime_error(
std::string(__func__) + ": No library found for API '"
+ spec.api + "'");
}
auto& lib = libOpt.value().get();
if (!lib.senseApiDesc.sal_mgmt_libOps.detachDeviceReq)
{
throw std::runtime_error(
std::string(__func__) + ": detachDeviceReq() is NULL for library '"
+ lib.libraryPath + "'");
}
lib.senseApiDesc.sal_mgmt_libOps.detachDeviceReq(spec);
}
void SenseApiManager::attachAllSenseDevicesFromSpecs(void)
{
for (const auto& spec : device::DeviceManager::senseDeviceSpecs) {
attachSenseDevice(*spec);
}
}
void SenseApiManager::detachAllSenseDevices(void)
{
for (const auto& spec : device::DeviceManager::senseDeviceSpecs) {
detachSenseDevice(*spec);
}
}
} // namespace sense_api
} // namespace hk
+9
View File
@@ -0,0 +1,9 @@
#ifndef HK_PREPROCESSOR_H
#define HK_PREPROCESSOR_H
#define HK_Q(x) #x
#define HK_QUOTE(x) HK_Q(x)
#define HK_UNMANGLED "C"
#endif // HK_PREPROCESSOR_H
+130
View File
@@ -0,0 +1,130 @@
#ifndef __USER_SENSE_API_LIB_H__
#define __USER_SENSE_API_LIB_H__
#include <preprocessor.h>
#include <stdbool.h>
#include <user/senseDeviceSpec.h>
namespace hk {
namespace sense_api {
/* Exported by all sense API Libraries to tell Harikoff what API the lib uses
* to connect to providers; and also to state which implexor APIs it exports.
*/
typedef int (sal_mho_initializeRdyFn)(void);
typedef int (sal_mho_finalizeRdyFn)(void);
typedef int (sal_mho_attachDeviceAckFn)(const device::SenseDeviceSpec &desc);
typedef int (sal_mho_detachDeviceAckFn)(const device::SenseDeviceSpec &desc);
struct Sal_Mgmt_HkOps
{
// Lib calls this function to notify Harikoff that it's done initializing.
sal_mho_initializeRdyFn *initializeRdy;
// Lib calls this function to notify Harikoff that it's done finalizing.
sal_mho_finalizeRdyFn *finalizeRdy;
// Lib calls this to notify Harikoff that it's done attaching a device.
sal_mho_attachDeviceAckFn *attachDeviceAck;
// Lib calls this to notify Harikoff that it's done detaching a device.
sal_mho_detachDeviceAckFn *detachDeviceAck;
};
typedef int (sal_mlo_initializeIndFn)(void);
typedef int (sal_mlo_finalizeIndFn)(void);
typedef int (sal_mlo_attachDeviceReqFn)(const device::SenseDeviceSpec &desc);
typedef int (sal_mlo_detachDeviceReqFn)(const device::SenseDeviceSpec &desc);
struct Sal_Mgmt_LibOps
{
/* When Harikoff loads a sense API lib, it calls this function to initialize
* the lib. When this returns, the lib should be ready to attach devices.
*/
sal_mlo_initializeIndFn *initializeInd;
/* Harikoff calls this to finalize the lib and free its internal
* resources. When this returns, the lib should be ready to be unloaded.
*/
sal_mlo_finalizeIndFn *finalizeInd;
/* Harikoff calls this to attach a device to the lib. When it returns, the
* device should be attached and ready to be implexed.
*/
sal_mlo_attachDeviceReqFn *attachDeviceReq;
// When this returns, the device should be detached.
sal_mlo_detachDeviceReqFn *detachDeviceReq;
static bool sanityCheck(const Sal_Mgmt_LibOps &ops)
{
if (!ops.initializeInd || !ops.finalizeInd
|| !ops.attachDeviceReq || !ops.detachDeviceReq)
{
return false;
}
return true;
}
};
/* C++ version of the C struct above, which Harikoff uses to manage the
* lib and connect implexors to it.
*/
class SenseApiDesc
{
public:
class ExportedImplexorApiDesc
{
public:
ExportedImplexorApiDesc(const std::string name)
// The caller should sanity check before calling this constructor.
: name(name)
{}
static bool sanityCheck(const ExportedImplexorApiDesc &desc)
{
if (desc.name.empty()) { return false; }
return true;
}
public:
std::string name;
};
public:
SenseApiDesc() = default;
std::string stringify() const
{
std::string result = "Name: " + name + "\n";
result += "Exported Implexor APIs:\n";
for (const auto& api : exportedImplexorApis) {
result += " - " + api.name + "\n";
}
return result;
}
static bool sanityCheck(const SenseApiDesc &desc)
{
if (desc.name.empty() || desc.exportedImplexorApis.empty()) {
return false;
}
for (const auto& api : desc.exportedImplexorApis) {
if (!ExportedImplexorApiDesc::sanityCheck(api)) { return false; }
}
return Sal_Mgmt_LibOps::sanityCheck(desc.sal_mgmt_libOps);
}
std::string name;
// These are the implexors whose APIs this lib exports.
std::vector<ExportedImplexorApiDesc> exportedImplexorApis;
Sal_Mgmt_LibOps sal_mgmt_libOps;
};
#define HK_GET_SENSE_API_DESC_FN_NAME getSenseApiDesc
#define HK_GET_SENSE_API_DESC_FN_NAME_STR \
HK_QUOTE(HK_GET_SENSE_API_DESC_FN_NAME)
typedef const SenseApiDesc &(getSenseApiDescFn)(void);
} // namespace sense_api
} // namespace hk
#endif // __USER_SENSE_API_LIB_H__
+77
View File
@@ -0,0 +1,77 @@
#ifndef SENSORDEVICESPEC_H
#define SENSORDEVICESPEC_H
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
namespace hk {
namespace device {
class SenseDeviceSpec
{
public:
friend std::ostream& operator<<(
std::ostream& os, const SenseDeviceSpec& spec)
{
os << spec.stringify();
return os;
}
bool operator==(const SenseDeviceSpec& other) const
{
return sensorType == other.sensorType &&
provider == other.provider &&
deviceSelector == other.deviceSelector;
}
public:
char sensorType;
std::string implexor;
std::string api;
std::vector<std::pair<std::string,std::string>> apiParams;
std::string provider;
std::vector<std::pair<std::string,std::string>> providerParams;
std::string deviceSelector;
std::string stringify() const
{
std::ostringstream os;
os << "Device: " << sensorType << ", Implexor: "
<< implexor << ", API: " << api << ", API Params: (";
for (const auto& param : apiParams)
{
os << param.first;
if (!param.second.empty()) {
os << "=" << param.second;
}
os << " ";
}
os << "), Provider: " << provider << ", Provider Params: (";
for (const auto& param : providerParams)
{
os << param.first;
if (!param.second.empty()) {
os << "=" << param.second;
}
os << " ";
}
os << "), Device Selector: " << deviceSelector << std::endl;
return os.str();
}
};
class InteroceptorDeviceSpec : public SenseDeviceSpec
{
};
class ExtrospectorDeviceSpec : public SenseDeviceSpec
{
};
} // namespace device
} // namespace hk
#endif // SENSORDEVICESPEC_H
+95
View File
@@ -0,0 +1,95 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_boost_asio.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_ASIO
#
# DESCRIPTION
#
# Test for Asio library from the Boost C++ libraries. The macro requires a
# preceding call to AX_BOOST_BASE. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_ASIO_LIB)
#
# And sets:
#
# HAVE_BOOST_ASIO
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
# Copyright (c) 2008 Pete Greenwell <pete@mu.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 18
AC_DEFUN([AX_BOOST_ASIO_gte_1_69_0],
[
AC_ARG_WITH([boost-asio],
AS_HELP_STRING([--with-boost-asio@<:@=special-lib@:>@],
[use the ASIO library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-asio=boost_system-gcc41-mt-1_34 ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_asio_lib=""
else
want_boost="yes"
ax_boost_user_asio_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::ASIO library is available,
ax_cv_boost_asio,
[AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @%:@include <boost/asio.hpp>
]],
[[
boost::asio::io_service io;
boost::system::error_code timer_result;
boost::asio::deadline_timer t(io);
t.cancel();
io.run_one();
return 0;
]])],
ax_cv_boost_asio=yes, ax_cv_boost_asio=no)
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_asio" = "xyes"; then
AC_DEFINE(HAVE_BOOST_ASIO,,
[define if the Boost::ASIO library is available])
BOOST_ASIO_LIB=""
AC_SUBST(BOOST_ASIO_LIB)
HAVE_BOOST_ASIO="yes"
else
HAVE_BOOST_ASIO="no"
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])
+305
View File
@@ -0,0 +1,305 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# DESCRIPTION
#
# Test for the Boost C++ libraries of a particular version (or newer)
#
# If no path to the installed boost library is given the macro searches
# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates
# the $BOOST_ROOT environment variable. Further documentation is available
# at <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
#
# And sets:
#
# HAVE_BOOST
#
# LICENSE
#
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
# Copyright (c) 2009 Peter Adolphs
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 55
# example boost program (need to pass version)
m4_define([_AX_BOOST_BASE_PROGRAM],
[AC_LANG_PROGRAM([[
#include <boost/version.hpp>
]],[[
(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))]));
]])])
AC_DEFUN([AX_BOOST_BASE],
[
AC_ARG_WITH([boost],
[AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
[use Boost library from a standard location (ARG=yes),
from the specified location (ARG=<path>),
or disable it (ARG=no)
@<:@ARG=yes@:>@ ])],
[
AS_CASE([$withval],
[no],[want_boost="no";_AX_BOOST_BASE_boost_path=""],
[yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""],
[want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"])
],
[want_boost="yes"])
AC_ARG_WITH([boost-libdir],
[AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
[Force given directory for boost libraries.
Note that this will override library path detection,
so use this parameter only if default library detection fails
and you know exactly where your boost libraries are located.])],
[
AS_IF([test -d "$withval"],
[_AX_BOOST_BASE_boost_lib_path="$withval"],
[AC_MSG_ERROR([--with-boost-libdir expected directory name])])
],
[_AX_BOOST_BASE_boost_lib_path=""])
BOOST_LDFLAGS=""
BOOST_CPPFLAGS=""
AS_IF([test "x$want_boost" = "xyes"],
[_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])])
AC_SUBST(BOOST_CPPFLAGS)
AC_SUBST(BOOST_LDFLAGS)
])
# convert a version string in $2 to numeric and affect to polymorphic var $1
AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[
AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"])
_AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'`
_AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'`
AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"],
[AC_MSG_ERROR([You should at least specify libboost major version])])
_AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'`
AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"],
[_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"])
_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"],
[_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"])
_AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor`
AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET)
])
dnl Run the detection of boost should be run only if $want_boost
AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
_AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1])
succeeded=no
AC_REQUIRE([AC_CANONICAL_HOST])
dnl On 64-bit systems check for system libraries in both lib64 and lib.
dnl The former is specified by FHS, but e.g. Debian does not adhere to
dnl this (as it rises problems for generic multi-arch support).
dnl The last entry in the list is chosen by default when no libraries
dnl are found, e.g. when only header-only libraries are installed!
AS_CASE([${host_cpu}],
[x86_64],[libsubdirs="lib64 libx32 lib lib64"],
[mips*64*],[libsubdirs="lib64 lib32 lib lib64"],
[ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k|loongarch64],[libsubdirs="lib64 lib lib64"],
[libsubdirs="lib"]
)
dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
dnl them priority over the other paths since, if libs are found there, they
dnl are almost assuredly the ones desired.
AS_CASE([${host_cpu}],
[i?86],[multiarch_libsubdir="lib/i386-${host_os}"],
[armv7l],[multiarch_libsubdir="lib/arm-${host_os}"],
[multiarch_libsubdir="lib/${host_cpu}-${host_os}"]
)
dnl first we check the system location for boost libraries
dnl this location is chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM
AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"])
AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[
AC_MSG_RESULT([yes])
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include"
for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"])
AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[
AC_MSG_RESULT([yes])
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp";
break;
],
[AC_MSG_RESULT([no])])
done],[
AC_MSG_RESULT([no])])
],[
if test X"$cross_compiling" = Xyes; then
search_libsubdirs=$multiarch_libsubdir
else
search_libsubdirs="$multiarch_libsubdir $libsubdirs"
fi
for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local /opt/homebrew ; do
if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then
for libsubdir in $search_libsubdirs ; do
if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir"
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include"
break;
fi
done
])
dnl overwrite ld flags if we have required special directory with
dnl --with-boost-libdir parameter
AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"],
[BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"])
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_REQUIRE([AC_PROG_CXX])
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
dnl if we found no boost with system layout we search for boost libraries
dnl built and installed without the --layout=system option or for a staged(not installed) version
if test "x$succeeded" != "xyes" ; then
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
BOOST_CPPFLAGS=
if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
BOOST_LDFLAGS=
fi
_version=0
if test -n "$_AX_BOOST_BASE_boost_path" ; then
if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then
for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "x$V_CHECK" = "x1" ; then
_version=$_version_tmp
fi
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE"
done
dnl if nothing found search for layout used in Windows distributions
if test -z "$BOOST_CPPFLAGS"; then
if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path"
fi
fi
dnl if we found something and BOOST_LDFLAGS was unset before
dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here.
if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then
for libsubdir in $libsubdirs ; do
if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir"
fi
fi
else
if test "x$cross_compiling" != "xyes" ; then
for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local /opt/homebrew ; do
if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then
for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "x$V_CHECK" = "x1" ; then
_version=$_version_tmp
best_path=$_AX_BOOST_BASE_boost_path
fi
done
fi
done
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
for libsubdir in $libsubdirs ; do
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
BOOST_LDFLAGS="-L$best_path/$libsubdir"
fi
fi
if test -n "$BOOST_ROOT" ; then
for libsubdir in $libsubdirs ; do
if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
V_CHECK=`expr $stage_version_shorten \>\= $_version`
if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
BOOST_CPPFLAGS="-I$BOOST_ROOT"
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
fi
fi
fi
fi
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
fi
if test "x$succeeded" != "xyes" ; then
if test "x$_version" = "x0" ; then
AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
else
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
fi
BOOST_LDFLAGS=""
BOOST_CPPFLAGS=""
# execute ACTION-IF-NOT-FOUND (if present):
ifelse([$3], , :, [$3])
else
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
# execute ACTION-IF-FOUND (if present):
ifelse([$2], , :, [$2])
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
])
+8427
View File
File diff suppressed because it is too large Load Diff
+437
View File
@@ -0,0 +1,437 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2022 Free
# Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 8 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option '$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
[_LT_WITH_AIX_SONAME([aix])])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [1], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the 'shared' and
# 'disable-shared' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the 'static' and
# 'disable-static' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the 'fast-install'
# and 'disable-fast-install' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_AIX_SONAME([DEFAULT])
# ----------------------------------
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
m4_define([_LT_WITH_AIX_SONAME],
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
shared_archive_member_spec=
case $host,$enable_shared in
power*-*-aix[[5-9]]*,yes)
AC_MSG_CHECKING([which variant of shared library versioning to provide])
AC_ARG_WITH([aix-soname],
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
[case $withval in
aix|svr4|both)
;;
*)
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
;;
esac
lt_cv_with_aix_soname=$with_aix_soname],
[AC_CACHE_VAL([lt_cv_with_aix_soname],
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
with_aix_soname=$lt_cv_with_aix_soname])
AC_MSG_RESULT([$with_aix_soname])
if test aix != "$with_aix_soname"; then
# For the AIX way of multilib, we name the shared archive member
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
# the AIX toolchain works better with OBJECT_MODE set (default 32).
if test 64 = "${OBJECT_MODE-32}"; then
shared_archive_member_spec=shr_64
else
shared_archive_member_spec=shr
fi
fi
;;
*)
with_aix_soname=aix
;;
esac
_LT_DECL([], [shared_archive_member_spec], [0],
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
])# _LT_WITH_AIX_SONAME
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
# LT_INIT options.
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for lt_pkg in $withval; do
IFS=$lt_save_ifs
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[pic_mode=m4_default([$1], [default])])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])
+124
View File
@@ -0,0 +1,124 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2022 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59, which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])
+24
View File
@@ -0,0 +1,24 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004, 2011-2019, 2021-2022 Free Software Foundation,
# Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# @configure_input@
# serial 4245 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.4.7])
m4_define([LT_PACKAGE_REVISION], [2.4.7])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.4.7'
macro_revision='2.4.7'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])
+99
View File
@@ -0,0 +1,99 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2022 Free
# Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 5 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
+22
View File
@@ -0,0 +1,22 @@
SENSEAPIS_ENABLED=
AC_ARG_ENABLE([senseapi-xcbxorg],
[AS_HELP_STRING([--enable-senseapi-xcbxorg],
[Enable XCB/Xorg SenseAPI backend])],
[AS_CASE([$enableval],
[no], [enable_senseapi_xcbxorg=no],
[yes|""|*], [
enable_senseapi_xcbxorg=yes
AC_DEFINE([XCBXORG_ENABLED], [1],
[Define to 1 if you have XCB/Xorg SenseAPI backend])
SENSEAPIS_ENABLED="${SENSEAPIS_ENABLED} xcbXorg"
PKG_CHECK_MODULES([XCB], [xcb], [], [
AC_MSG_ERROR(m4_normalize([XCB library not found. Sense API
XCB/Xorg requires the XCB dev headers and shlib.]))
])
AC_SUBST([XCB_CFLAGS])
AC_SUBST([XCB_LIBS])
]
)],
[enable_senseapi_xcbxorg=no]
)
+86 -22
View File
@@ -1,44 +1,108 @@
#include <iostream>
#include <exception>
#include <thread>
#include <mutex>
#include <unordered_map>
#include <condition_variable>
#include <boost/asio.hpp>
#include <opts.h>
#include <mind.h>
#include <deviceManager/deviceManager.h>
#include <senseApis/senseApiManager.h>
#include "componentThread.h"
int main(int argc, char **argv)
namespace hk {
static int initializeHarikoff(int argc, char **argv, char **envp);
} // namespace hk
int main(int argc, char **argv, char **envp)
{
try {
OptionParser options;
try {
std::cout << __func__ << ": Entering main()" << std::endl;
boost::asio::io_service mrntLoop;
boost::asio::io_service::work work(mrntLoop);
// Validate thread IDs
hk::ComponentThread::validateThreadIds();
// Post initializeHarikoff to mrntLoop
mrntLoop.post([&]()
{
int ret = hk::initializeHarikoff(argc, argv, envp);
if (ret != 0)
{
std::cerr << "Initialization failed with code: "
<< ret << std::endl;
std::exit(ret);
}
});
mrntLoop.run();
}
catch (const std::exception& e)
{
std::cerr << __func__ << ": Exception occurred: " << e.what()
<< std::endl;
return EXIT_FAILURE;
}
catch (...)
{
std::cerr << __func__ << ": Unknown exception occurred" << std::endl;
return EXIT_FAILURE;
}
std::cout << __func__ << ": Exiting normally" << std::endl;
return 0;
}
namespace hk {
static int initializeHarikoff(int argc, char **argv, char **envp)
{
std::cout << __func__ << ": Entering" << std::endl;
using namespace hk;
OptionParser &options = OptionParser::getOptions();
hk::Mind mind;
std::cout << PACKAGE_NAME << " " << PACKAGE_VERSION << std::endl;
try {
options.parseArguments(argc, argv);
options.parseArguments(argc, argv, envp);
std::cout << options.stringifyOptions() << std::endl;
}
catch (const std::invalid_argument& e) {
std::cerr << e.what() << '\n' << options.getUsage() << '\n';
catch (const std::invalid_argument& e)
{
std::cerr << __func__ << ": Exception occurred: " << e.what() << '\n'
<< options.getUsage() << '\n';
return EXIT_FAILURE;
}
if (options.printUsage) {
if (options.printUsage)
{
std::cout << options.getUsage() << std::endl;
return EXIT_SUCCESS;
}
options.dumpOptions();
DeviceManager::getInstance().collateAllDeviceSpecs(options);
DeviceManager::getInstance().parseAllDeviceSpecs();
std::cout << DeviceManager::printDeviceSpecs() << std::endl;
}
catch (const std::exception& e) {
std::cerr << "Exception occurred: " << e.what() << std::endl;
return EXIT_FAILURE;
}
catch (...) {
std::cerr << "Unknown exception occurred" << std::endl;
return EXIT_FAILURE;
device::DeviceManager::getInstance().collateAllDeviceSpecs();
device::DeviceManager::getInstance().parseAllDeviceSpecs();
std::cout << device::DeviceManager::stringifyDeviceSpecs() << std::endl;
sense_api::SenseApiManager::getInstance().loadAllSenseApiLibsFromOptions();
std::cout << sense_api::SenseApiManager::getInstance().stringifyLibs()
<< std::endl;
sense_api::SenseApiManager::getInstance().initializeAllSenseApiLibs();
sense_api::SenseApiManager::getInstance().attachAllSenseDevicesFromSpecs();
/* Start the threads */
for (const auto& [id, componentThread]
: hk::ComponentThread::componentThreads) {
hk::ComponentThread::signalThread(id);
}
std::cout << __func__ << ": Exiting" << std::endl;
return 0;
}
std::cout << "Exiting normally" << std::endl;
return 0;
}
} // namespace hk
+1
View File
@@ -0,0 +1 @@
SUBDIRS = @SENSEAPIS_ENABLED@
+6
View File
@@ -0,0 +1,6 @@
pkglib_LTLIBRARIES=libxcbXorg.la
libxcbXorg_la_SOURCES=xcbXorg.cpp
libxcbXorg_la_LDFLAGS=$(XCB_LIBS)
xcbXorg.$(OBJEXT): CPPFLAGS+=$(XCB_CFLAGS) -Wno-c++20-extensions
xcbXorg.l$(OBJEXT): CPPFLAGS+=$(XCB_CFLAGS) -Wno-c++20-extensions
+527
View File
@@ -0,0 +1,527 @@
#include <iostream>
#include <algorithm>
#include <stdexcept>
#include <memory>
#include <vector>
#include <sstream>
#include <map>
#include <atomic>
#include <user/senseDeviceSpec.h>
#include <user/senseApiDesc.h>
#include <xcb/xcb.h>
#include "xcbXorg.h"
// Key for identifying unique X server connections
struct XcbConnection
{
struct XConnectionIdentifier
{
int display;
int screen;
bool operator<(const XConnectionIdentifier& other) const
{
if (display != other.display) return display < other.display;
return screen < other.screen;
}
std::string stringify() const
{
std::ostringstream os;
os << "display=" << display << ", screen=" << screen;
return os.str();
}
};
/**
* @brief RAII guard for managing X server connection lifetime
*
* This guard ensures proper cleanup of X server connections in case of
* errors during attachDeviceReq. If a connection is created but the device
* attachment fails, and the connection's refcount is 0, this guard will
* automatically remove the connection from the connections map.
*
* The guard can be "committed" using commit() to indicate successful
* device attachment, in which case it will not perform cleanup on destruction.
*/
class ConnectionGuard
{
std::shared_ptr<XcbConnection> conn;
bool committed = false;
public:
explicit ConnectionGuard(std::shared_ptr<XcbConnection> c)
: conn(std::move(c))
{}
void commit(void) { committed = true; }
~ConnectionGuard()
{
if (!committed && conn && conn->refCount == 0) {
XcbConnection::connections.erase(conn->connectionIdentifier);
}
}
};
XcbConnection(const XConnectionIdentifier& id)
: connection(nullptr, &xcb_disconnect),
connectionIdentifier(id), refCount(0)
{
// Convert to X display string format (e.g., ":0.1")
std::string displayString = ":" + std::to_string(id.display)
+ "." + std::to_string(id.screen);
int screenNum;
connection.reset(xcb_connect(displayString.c_str(), &screenNum));
if (xcb_connection_has_error(connection.get()))
{
throw std::runtime_error(
std::string(__func__) + ": Failed to connect to X server "
+ connectionIdentifier.stringify());
}
// Verify we got the screen we asked for
if (screenNum != id.screen)
{
throw std::runtime_error(
std::string(__func__) + ": Connected to wrong screen. "
"Requested " + connectionIdentifier.stringify()
+ " but got screen " + std::to_string(screenNum));
}
}
// Delete copy/move operations - we'll manage instances through pointers
XcbConnection(const XcbConnection&) = delete;
XcbConnection& operator=(const XcbConnection&) = delete;
XcbConnection(XcbConnection&&) = delete;
XcbConnection& operator=(XcbConnection&&) = delete;
std::unique_ptr<xcb_connection_t, decltype(&xcb_disconnect)> connection;
XConnectionIdentifier connectionIdentifier;
std::atomic<int> refCount;
public:
static std::map<XConnectionIdentifier, std::shared_ptr<XcbConnection>>
connections;
static std::shared_ptr<XcbConnection> getOrCreateConnection(
const XConnectionIdentifier& id)
{
auto it = connections.find(id);
if (it != connections.end()) {
return it->second;
}
auto conn = std::make_shared<XcbConnection>(id);
connections.emplace(id, conn);
return conn;
}
};
namespace xcb_window_search {
// Custom deleters for XCB reply types
struct XcbReplyDeleter {
void operator()(xcb_query_tree_reply_t* p) { free(p); }
void operator()(xcb_get_property_reply_t* p) { free(p); }
};
enum class MatchType { SUBSTRING, EXACT, ID };
static xcb_window_t findById(
xcb_connection_t* conn, xcb_window_t root, uint32_t targetId);
static xcb_window_t findByName(
xcb_connection_t* conn, xcb_window_t root,
const std::string& targetName, std::string& outWindowName,
MatchType matchType);
}
class AttachedDevice
{
public:
struct WindowSelector
{
xcb_window_search::MatchType matchType;
XcbConnection::XConnectionIdentifier xconn;
struct
{
uint32_t id;
std::string name;
} window;
std::string stringify() const
{
std::ostringstream os;
os << "Display: " << xconn.display
<< ", Screen: " << xconn.screen << ", Window: ";
if (matchType == xcb_window_search::MatchType::ID) {
os << window.id;
} else {
os << "\"" << window.name << "\"";
}
os << " (matchType="
<< (matchType == xcb_window_search::MatchType::EXACT
? "exact" :
(matchType == xcb_window_search::MatchType::SUBSTRING)
? "substring" : "id")
<< ")";
return os.str();
}
};
AttachedDevice(const hk::device::SenseDeviceSpec &spec,
std::shared_ptr<XcbConnection> conn)
: deviceSpec(spec)
// This std::move is moving ownership from a shared_ptr to a shared_ptr
, connection(std::move(conn))
{
windowSelector.xconn.display = getRequiredParamAsInt(spec, "display");
windowSelector.xconn.screen = getRequiredParamAsInt(spec, "screen");
parseWindowSelector(spec, windowSelector);
// Get the root window
const xcb_setup_t* setup = xcb_get_setup(connection->connection.get());
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
for (int i = 0; i < windowSelector.xconn.screen; ++i) {
xcb_screen_next(&iter);
}
xcb_window_t root = iter.data->root;
// Search for window
xcb_window_t targetWindow = 0;
if (windowSelector.matchType == xcb_window_search::MatchType::ID)
{
targetWindow = xcb_window_search::findById(
connection->connection.get(), root, windowSelector.window.id);
}
else
{
targetWindow = xcb_window_search::findByName(
connection->connection.get(), root,
windowSelector.window.name, actualWindowName,
windowSelector.matchType);
}
if (!targetWindow)
{
throw std::runtime_error(
"Failed to find window "
+ (windowSelector.matchType == xcb_window_search::MatchType::ID
? std::to_string(windowSelector.window.id)
: "\"" + windowSelector.window.name + "\"")
+ " on display " + std::to_string(windowSelector.xconn.display)
+ ", screen " + std::to_string(windowSelector.xconn.screen));
}
}
hk::device::SenseDeviceSpec deviceSpec;
WindowSelector windowSelector;
std::shared_ptr<XcbConnection> connection;
std::string actualWindowName;
public:
static int getRequiredParamAsInt(
const hk::device::SenseDeviceSpec& spec,
const std::string& paramName)
{
auto it = std::find_if(
spec.providerParams.begin(),
spec.providerParams.end(),
[&paramName](const auto& param) {
return param.first == paramName;
}
);
if (it == spec.providerParams.end())
{
throw std::runtime_error(
"No " + paramName + " specified in provider params");
}
try {
return std::stoi(it->second);
} catch (const std::exception& e) {
throw std::runtime_error(
"Failed to parse '" + paramName + "' param value '"
+ it->second + "' as integer: " + e.what());
}
}
static void parseWindowSelector(
const hk::device::SenseDeviceSpec& spec,
WindowSelector& windowSelector)
{
// Default match type
windowSelector.matchType = xcb_window_search::MatchType::SUBSTRING;
// Check if 'dev-id', 'dev-string', or 'dev-substring' is specified
for (const auto& param : spec.apiParams)
{
if (param.first == "dev-id" || param.first == "devid")
{
windowSelector.matchType = xcb_window_search::MatchType::ID;
break;
}
if (param.first == "dev-string" || param.first == "dev-str"
|| param.first == "devstr" || param.first == "devstring")
{
windowSelector.matchType = xcb_window_search::MatchType::EXACT;
}
if (param.first == "dev-substring" || param.first == "dev-substr"
|| param.first == "devsubstr" || param.first == "devsubstring")
{
windowSelector.matchType = xcb_window_search::
MatchType::SUBSTRING;
}
}
if (windowSelector.matchType == xcb_window_search::MatchType::ID)
{
try {
windowSelector.window.id = std::stoul(
spec.deviceSelector, nullptr, 0);
} catch (const std::exception&) {
throw std::runtime_error(
"Window selector: 'dev-id' present, but selector is not "
"numeric");
}
}
else {
windowSelector.window.name = spec.deviceSelector;
}
}
};
// Define the static member
std::map<XcbConnection::XConnectionIdentifier, std::shared_ptr<XcbConnection>>
XcbConnection::connections;
static std::vector<AttachedDevice> attachedDevices;
namespace xcb_window_search {
static xcb_window_t findById(
xcb_connection_t* conn, xcb_window_t root, uint32_t targetId)
{
xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root);
std::unique_ptr<xcb_query_tree_reply_t, XcbReplyDeleter> reply(
xcb_query_tree_reply(conn, cookie, nullptr));
if (!reply) return 0;
// First check if current window is the target
if (root == targetId) {
return root;
}
// Then check all children
xcb_window_t* children = xcb_query_tree_children(reply.get());
int num_children = xcb_query_tree_children_length(reply.get());
for (int i = 0; i < num_children; ++i)
{
if (children[i] == targetId) {
return children[i];
}
// Recursively search this child's subtree
if (xcb_window_t result = findById(
conn, children[i], targetId))
{
return result;
}
}
return 0;
}
static xcb_window_t findByName(
xcb_connection_t* conn, xcb_window_t root,
const std::string& targetName, std::string& outWindowName,
MatchType matchType)
{
xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root);
std::unique_ptr<xcb_query_tree_reply_t, XcbReplyDeleter> reply(
xcb_query_tree_reply(conn, cookie, nullptr));
if (!reply) return 0;
// First check current window
xcb_get_property_cookie_t prop_cookie = xcb_get_property(
conn, 0, root, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1024);
std::unique_ptr<xcb_get_property_reply_t, XcbReplyDeleter> prop_reply(
xcb_get_property_reply(conn, prop_cookie, nullptr));
if (prop_reply)
{
int len = xcb_get_property_value_length(prop_reply.get());
char* name = static_cast<char*>(
xcb_get_property_value(prop_reply.get()));
if (len > 0)
{
std::string windowName(name, len);
if ((matchType == MatchType::EXACT
&& windowName == targetName)
|| (matchType == MatchType::SUBSTRING
&& windowName.find(targetName) != std::string::npos))
{
outWindowName = windowName;
return root;
}
}
}
// Then check all children
xcb_window_t* children = xcb_query_tree_children(reply.get());
int num_children = xcb_query_tree_children_length(reply.get());
for (int i = 0; i < num_children; ++i)
{
prop_cookie = xcb_get_property(
conn, 0, children[i],
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1024);
prop_reply.reset(xcb_get_property_reply(conn, prop_cookie, nullptr));
if (prop_reply)
{
int len = xcb_get_property_value_length(prop_reply.get());
char* name = static_cast<char*>(xcb_get_property_value(
prop_reply.get()));
if (len > 0)
{
std::string windowName(name, len);
if ((matchType == MatchType::EXACT
&& windowName == targetName)
|| (matchType == MatchType::SUBSTRING
&& windowName.find(targetName) != std::string::npos))
{
outWindowName = windowName;
return children[i];
}
}
}
// Recursively search this child's subtree
if (xcb_window_t result = findByName(
conn, children[i], targetName, outWindowName, matchType))
{
return result;
}
}
return 0;
}
} // namespace xcb_window_search
static hk::sense_api::sal_mlo_initializeIndFn xcbXorg_initializeInd;
static hk::sense_api::sal_mlo_finalizeIndFn xcbXorg_finalizeInd;
static hk::sense_api::sal_mlo_attachDeviceReqFn xcbXorg_attachDeviceReq;
static hk::sense_api::sal_mlo_detachDeviceReqFn xcbXorg_detachDeviceReq;
static hk::sense_api::SenseApiDesc xcbXorgApiDesc =
{
.name = "xcb",
.exportedImplexorApis = { { "video-implexor" } },
.sal_mgmt_libOps = {
.initializeInd = xcbXorg_initializeInd,
.finalizeInd = xcbXorg_finalizeInd,
.attachDeviceReq = xcbXorg_attachDeviceReq,
.detachDeviceReq = xcbXorg_detachDeviceReq
}
};
extern HK_UNMANGLED hk::sense_api::getSenseApiDescFn
HK_GET_SENSE_API_DESC_FN_NAME;
const hk::sense_api::SenseApiDesc &HK_GET_SENSE_API_DESC_FN_NAME(void)
{
return xcbXorgApiDesc;
}
int xcbXorg_initializeInd(void)
{
return 0;
}
int xcbXorg_finalizeInd(void)
{
XcbConnection::connections.clear();
return 0;
}
int xcbXorg_attachDeviceReq(const hk::device::SenseDeviceSpec &desc)
{
// Ensure connection exists before creating device. Create conn'tion if not.
XcbConnection::XConnectionIdentifier id{
AttachedDevice::getRequiredParamAsInt(desc, "display"),
AttachedDevice::getRequiredParamAsInt(desc, "screen")
};
auto conn = XcbConnection::getOrCreateConnection(id);
// RAII protection in case AttachDevice construction below fails
XcbConnection::ConnectionGuard guard(conn);
// Create device and increment connection refcount
attachedDevices.emplace_back(desc, conn);
// Successfully attached device, so decouple guard from RAII cleanup
conn->refCount++;
guard.commit();
std::cout << "Attaching X11 window:\n "
<< attachedDevices.back().windowSelector.stringify() << "\n"
<< " Actual window name: \""
<< attachedDevices.back().actualWindowName << "\"\n"
<< " Using " << (conn->refCount > 1 ? "existing" : "new")
<< " connection to X server\n";
return 0;
}
int xcbXorg_detachDeviceReq(const hk::device::SenseDeviceSpec &spec)
{
auto it = std::find_if(attachedDevices.begin(), attachedDevices.end(),
[&spec](const AttachedDevice &device) {
return device.deviceSpec == spec;
}
);
if (it == attachedDevices.end())
{
auto displayIt = std::find_if(
spec.providerParams.begin(), spec.providerParams.end(),
[](const auto& param) { return param.first == "display"; });
auto screenIt = std::find_if(
spec.providerParams.begin(), spec.providerParams.end(),
[](const auto& param) { return param.first == "screen"; });
std::cerr << __func__ << ": Device not attached: "
<< "display=" << (displayIt != spec.providerParams.end()
? displayIt->second : "not specified")
<< ", screen=" << (screenIt != spec.providerParams.end()
? screenIt->second : "not specified")
<< ", selector=" << spec.deviceSelector << "\n";
return 0;
}
XcbConnection::XConnectionIdentifier id{
it->windowSelector.xconn.display,
it->windowSelector.xconn.screen
};
// Atomic decrement refcount
int newCount = --it->connection->refCount;
// If no more references, close the connection
if (newCount == 0)
{
XcbConnection::connections.erase(id);
std::cout << "Closed X server connection (display="
<< id.display << ", screen=" << id.screen << ")\n";
}
attachedDevices.erase(it);
std::cout << __func__ << ": Detached device\n";
return 0;
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef X11_XCB_API_H
#define X11_XCB_API_H
#include <string>
#include <vector>
#include <memory>
#include <user/senseApiDesc.h>
class Xcb_XorgApi
{
public:
Xcb_XorgApi(const std::string& _displayName)
: displayName(_displayName)
{}
~Xcb_XorgApi() = default;
private:
std::string displayName;
};
#endif // X11_XCB_API_H