Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ jobs:
with:
targets: ${{ matrix.target }}

- name: Set up Python
if: contains(matrix.target, 'windows')
uses: actions/setup-python@v6
with:
python-version: '3.13'
architecture: ${{ matrix.msvc_arch }}

- name: Initialize MSVC developer command prompt
if: contains(matrix.target, 'windows')
uses: ilammy/msvc-dev-cmd@v1
Expand Down Expand Up @@ -137,6 +144,19 @@ jobs:
}
"runtime-lib=$runtime" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8

- name: Find decode runtime library (Windows)
if: matrix.package_bundle && contains(matrix.target, 'windows')
id: find-decode-runtime-windows
shell: pwsh
run: |
$runtime = Get-ChildItem "target/${{ matrix.target }}/release/build" -Recurse -Filter "dsview_decode_runtime.dll" -ErrorAction Stop |
Sort-Object FullName |
Select-Object -First 1 -ExpandProperty FullName
if (-not $runtime) {
throw "Windows decode runtime library was not found under target/${{ matrix.target }}/release/build"
}
"runtime-lib=$runtime" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8

- name: Find runtime library (Unix)
if: matrix.package_bundle && !contains(matrix.target, 'windows')
id: find-runtime-unix
Expand All @@ -153,6 +173,22 @@ jobs:
fi
echo "runtime-lib=$RUNTIME_LIB" >> "$GITHUB_OUTPUT"

- name: Find decode runtime library (Unix)
if: matrix.package_bundle && !contains(matrix.target, 'windows')
id: find-decode-runtime-unix
shell: bash
run: |
if [[ "${{ matrix.target }}" == *"darwin"* ]] || [[ "${{ matrix.target }}" == *"macos"* ]]; then
RUNTIME_LIB=$(find target/${{ matrix.target }}/release/build/dsview-sys-*/out/source-decode-runtime-build -name "libdsview_decode_runtime.dylib" -print -quit)
else
RUNTIME_LIB=$(find target/${{ matrix.target }}/release/build/dsview-sys-*/out/source-decode-runtime-build -name "libdsview_decode_runtime.so" -print -quit)
fi
if [[ -z "$RUNTIME_LIB" ]]; then
echo "decode runtime library was not found for ${{ matrix.target }}" >&2
exit 1
fi
echo "runtime-lib=$RUNTIME_LIB" >> "$GITHUB_OUTPUT"

- name: Determine executable path
if: matrix.package_bundle
id: exe-path
Expand All @@ -172,3 +208,5 @@ jobs:
version: ${{ steps.version.outputs.version }}
exe-path: ${{ steps.exe-path.outputs.exe }}
runtime-path: ${{ contains(matrix.target, 'windows') && steps.find-runtime-windows.outputs.runtime-lib || steps.find-runtime-unix.outputs.runtime-lib }}
decode-runtime-path: ${{ contains(matrix.target, 'windows') && steps.find-decode-runtime-windows.outputs.runtime-lib || steps.find-decode-runtime-unix.outputs.runtime-lib }}
decoder-dir: DSView/libsigrokdecode4DSL/decoders
7 changes: 7 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ jobs:
with:
targets: ${{ matrix.target }}

- name: Set up Python
if: contains(matrix.target, 'windows')
uses: actions/setup-python@v6
with:
python-version: '3.13'
architecture: ${{ matrix.msvc_arch }}

- name: Initialize MSVC developer command prompt
if: contains(matrix.target, 'windows')
uses: ilammy/msvc-dev-cmd@v1
Expand Down
33 changes: 31 additions & 2 deletions crates/dsview-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const BUNDLED_RUNTIME_DIR: &str = "runtime";
const BUNDLED_RESOURCE_DIR: &str = "resources";
const BUNDLED_DECODE_RUNTIME_DIR: &str = "decode-runtime";
const BUNDLED_DECODER_DIR: &str = "decoders";
const BUNDLED_PYTHON_DIR: &str = "python";

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SelectionHandle(NonZeroU64);
Expand Down Expand Up @@ -1221,6 +1222,7 @@ pub struct RuntimeDiscoveryPaths {
pub struct DecodeDiscoveryPaths {
pub runtime_library: PathBuf,
pub decoder_dir: PathBuf,
pub python_home: Option<PathBuf>,
}

impl RuntimeDiscoveryPaths {
Expand Down Expand Up @@ -1305,6 +1307,7 @@ impl DecodeDiscoveryPaths {
.join(BUNDLED_DECODE_RUNTIME_DIR)
.join(decode_runtime_library_name());
let bundled_decoder_dir = executable_dir.join(BUNDLED_DECODER_DIR);
let bundled_python_home = executable_dir.join(BUNDLED_PYTHON_DIR);

let runtime_library = if let Some(path) = runtime_override {
path
Expand All @@ -1329,11 +1332,21 @@ impl DecodeDiscoveryPaths {
developer_decoder_dir()
};

let python_home = if cfg!(windows)
&& runtime_library == bundled_runtime
&& bundled_python_home.is_dir()
{
Some(bundled_python_home)
} else {
None
};

ensure_decoder_script_dir(&decoder_dir)?;

Ok(Self {
runtime_library,
decoder_dir,
python_home,
})
}
}
Expand Down Expand Up @@ -1778,18 +1791,30 @@ impl DecodeDiscovery {
pub fn connect(
library_path: impl AsRef<Path>,
decoder_dir: impl AsRef<Path>,
) -> Result<Self, DecodeBringUpError> {
Self::connect_with_python_home(library_path, decoder_dir, None::<&Path>)
}

pub fn connect_with_python_home(
library_path: impl AsRef<Path>,
decoder_dir: impl AsRef<Path>,
python_home: Option<impl AsRef<Path>>,
) -> Result<Self, DecodeBringUpError> {
let library_path = library_path.as_ref().to_path_buf();
let decoder_dir = decoder_dir.as_ref().to_path_buf();
let python_home = python_home.map(|path| path.as_ref().to_path_buf());
ensure_decoder_script_dir(&decoder_dir)?;
let runtime =
DecodeRuntimeBridge::load(&library_path).map_err(DecodeBringUpError::Runtime)?;
runtime.init(&decoder_dir).map_err(DecodeBringUpError::Runtime)?;
runtime
.init_with_python_home(&decoder_dir, python_home.as_deref())
.map_err(DecodeBringUpError::Runtime)?;
Ok(Self {
runtime,
paths: DecodeDiscoveryPaths {
runtime_library: library_path,
decoder_dir,
python_home,
},
})
}
Expand All @@ -1799,7 +1824,11 @@ impl DecodeDiscovery {
decoder_dir_override: Option<impl AsRef<Path>>,
) -> Result<Self, DecodeBringUpError> {
let paths = DecodeDiscoveryPaths::discover(runtime_override, decoder_dir_override)?;
Self::connect(&paths.runtime_library, &paths.decoder_dir)
Self::connect_with_python_home(
&paths.runtime_library,
&paths.decoder_dir,
paths.python_home.as_deref(),
)
}

pub fn discovery_paths(
Expand Down
4 changes: 4 additions & 0 deletions crates/dsview-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ fn main() {
"cargo:rerun-if-changed={}",
native_root.join("windows/dsview_runtime.def").display()
);
println!(
"cargo:rerun-if-changed={}",
native_root.join("windows/dsview_decode_runtime.def").display()
);
println!(
"cargo:rerun-if-changed={}",
compat_root.join("msvc_preinclude.h").display()
Expand Down
9 changes: 9 additions & 0 deletions crates/dsview-sys/compat/msvc_decode_preinclude.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
#define NOMINMAX 1
#endif

/*
* libsigrokdecode4DSL still carries GCC-style attributes in a few source
* files. MSVC rejects these declarations unless they are normalized away
* before the upstream sources are compiled.
*/
#ifndef __attribute__
#define __attribute__(x)
#endif

#include <BaseTsd.h>
#include <winsock2.h>
#include <ws2tcpip.h>
Expand Down
13 changes: 13 additions & 0 deletions crates/dsview-sys/native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,23 @@ if(DSVIEW_BUILD_DECODE_RUNTIME)
Python3::Python
)

if(WIN32 AND DEFINED Python3_LIBRARY_RELEASE)
get_filename_component(PYTHON3_LIBRARY_DIR "${Python3_LIBRARY_RELEASE}" DIRECTORY)
target_link_directories(dsview_decode_runtime PRIVATE
"${PYTHON3_LIBRARY_DIR}"
)
endif()

target_link_directories(dsview_decode_runtime PRIVATE
${GLIB_LIBRARY_DIRS}
)

if(MSVC)
set_target_properties(dsview_decode_runtime PROPERTIES
LINK_FLAGS "/DEF:${DSVIEW_NATIVE_WINDOWS_ROOT}/dsview_decode_runtime.def"
)
endif()

set_target_properties(dsview_decode_runtime PROPERTIES OUTPUT_NAME dsview_decode_runtime)
configure_runtime_target(dsview_decode_runtime msvc_decode_preinclude.h)
endif()
20 changes: 20 additions & 0 deletions crates/dsview-sys/native/windows/dsview_decode_runtime.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
LIBRARY dsview_decode_runtime
EXPORTS
srd_init
srd_exit
srd_decoder_list
srd_decoder_get_by_id
srd_decoder_load_all
srd_searchpaths_get
srd_strerror
srd_strerror_name
srd_session_new
srd_session_metadata_set
srd_session_start
srd_session_send
srd_session_end
srd_session_destroy
srd_pd_output_callback_add
srd_inst_new
srd_inst_channel_set_all
srd_inst_stack
57 changes: 55 additions & 2 deletions crates/dsview-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
//! This crate is the only allowed home for unsafe FFI when Phase 1 adds
//! bindings to `DSView/libsigrok4DSL`.

use std::cell::Cell;
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
use std::env;
use std::ffi::{CStr, CString, OsString};
use std::fmt;
use std::fs;
use std::os::raw::{c_char, c_int};
Expand Down Expand Up @@ -1867,6 +1868,7 @@ impl Drop for RuntimeBridge {
pub struct DecodeRuntimeBridge {
library_path: PathBuf,
initialized: Cell<bool>,
python_home_guard: RefCell<Option<PythonHomeGuard>>,
}

impl DecodeRuntimeBridge {
Expand All @@ -1885,6 +1887,7 @@ impl DecodeRuntimeBridge {
0 => Ok(Self {
library_path: path.to_path_buf(),
initialized: Cell::new(false),
python_home_guard: RefCell::new(None),
}),
DSVIEW_BRIDGE_ERR_ARG | DSVIEW_DECODE_ERR_ARG => Err(DecodeRuntimeError::InvalidArgument(
"decode runtime library path must not be empty".to_string(),
Expand All @@ -1911,10 +1914,24 @@ impl DecodeRuntimeBridge {
}

pub fn init(&self, decoder_dir: impl AsRef<Path>) -> Result<(), DecodeRuntimeError> {
self.init_with_python_home(decoder_dir, None::<&Path>)
}

pub fn init_with_python_home(
&self,
decoder_dir: impl AsRef<Path>,
python_home: Option<impl AsRef<Path>>,
) -> Result<(), DecodeRuntimeError> {
let guard = if let Some(path) = python_home {
Some(PythonHomeGuard::activate(path.as_ref())?)
} else {
None
};
let c_path = path_to_decode_cstring(decoder_dir.as_ref())?;
decode_native_call_status("decode runtime init", unsafe {
dsview_decode_runtime_init(c_path.as_ptr())
})?;
*self.python_home_guard.borrow_mut() = guard;
self.initialized.set(true);
Ok(())
}
Expand All @@ -1924,6 +1941,7 @@ impl DecodeRuntimeBridge {
dsview_decode_runtime_exit()
})?;
self.initialized.set(false);
self.python_home_guard.borrow_mut().take();
Ok(())
}

Expand Down Expand Up @@ -2002,6 +2020,41 @@ impl Drop for DecodeRuntimeBridge {
let _ = dsview_decode_runtime_exit();
};
}
self.python_home_guard.get_mut().take();
}
}

#[derive(Debug)]
struct PythonHomeGuard {
previous_home: Option<OsString>,
}

impl PythonHomeGuard {
fn activate(path: &Path) -> Result<Self, DecodeRuntimeError> {
if !path.is_dir() {
return Err(DecodeRuntimeError::InvalidArgument(format!(
"python home path does not exist: {}",
path.display()
)));
}

let previous_home = env::var_os("PYTHONHOME");
unsafe {
env::set_var("PYTHONHOME", path);
}
Ok(Self { previous_home })
}
}

impl Drop for PythonHomeGuard {
fn drop(&mut self) {
unsafe {
if let Some(previous_home) = &self.previous_home {
env::set_var("PYTHONHOME", previous_home);
} else {
env::remove_var("PYTHONHOME");
}
}
}
}

Expand Down
Loading
Loading