feat: small command line helpers for quick tests (#4272)
* feat: small command line helpers for quick tests
Add --cflags, --ldflags, --embed, and --file to the pybind11 command
line tool, based on python-config. This makes quick one-off compiles
easy:
c++ $(python3 -m pybind11 --file=example.cpp)
Assisted-by: ClaudeCode:claude-fable-5
* refactor: quote paths, clarify CLI output logic, strengthen tests
- Quote include and library dirs in get_cflags/get_ldflags so paths with
spaces work, sharing one quote helper in commands.py
- Restructure the --file/--cflags/--ldflags printing into a single print
- Note the Unix-compiler orientation in help text and docs
- Test -L presence for --embed and quoting of paths with spaces
Assisted-by: ClaudeCode:claude-fable-5
* refactor: simplify flag helpers and keep import pybind11 light
- Replace _get_config_var(name, fmt, quote) with a plain _config(name)
string helper; formatting and quoting happen at the call sites
- Defer sysconfig/shlex imports so import pybind11 does not pay for the
CLI (~1ms -> ~0.08ms for pybind11.commands)
- Fetch EXT_SUFFIX once in main()
- Import commands normally in the quoting test instead of importlib
file loading
Assisted-by: ClaudeCode:claude-fable-5
* fix: shared-library flags on all Unix platforms
The --file/--ldflags output only added -shared and -fPIC on Linux, so
other Unix platforms (FreeBSD, Solaris, AIX) linked an executable and
failed on the missing main. Gate on os.name instead.
Assisted-by: ClaudeCode:claude-opus-5
This commit is contained in:
@@ -1,16 +1,20 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import importlib
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import sysconfig
|
||||
import tarfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
|
||||
import pytest
|
||||
|
||||
# These tests must be run explicitly
|
||||
|
||||
DIR = Path(__file__).parent.resolve()
|
||||
@@ -384,3 +388,63 @@ def test_version_matches():
|
||||
expected_patch = f"{micro}{level_str}{release_serial}"
|
||||
|
||||
assert patch == expected_patch
|
||||
|
||||
|
||||
def run_command_line(*args: str) -> str:
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = str(MAIN_DIR)
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "pybind11", *args],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
env=env,
|
||||
)
|
||||
return result.stdout
|
||||
|
||||
|
||||
def test_cli_cflags():
|
||||
out = run_command_line("--cflags")
|
||||
assert "-std=c++17" in out
|
||||
assert f"-I{sysconfig.get_path('include')}" in out
|
||||
|
||||
|
||||
def test_cli_ldflags_embed():
|
||||
out = run_command_line("--ldflags", "--embed")
|
||||
assert "-lpython" in out
|
||||
if sysconfig.get_config_var("LIBDIR"):
|
||||
assert "-L" in out
|
||||
|
||||
|
||||
@pytest.mark.skipif(os.name != "posix", reason="quote style is platform-specific")
|
||||
def test_cflags_quotes_paths_with_spaces(monkeypatch):
|
||||
monkeypatch.syspath_prepend(str(MAIN_DIR))
|
||||
commands = importlib.import_module("pybind11.commands")
|
||||
monkeypatch.setattr(sysconfig, "get_path", lambda name: f"/spa ced/{name}")
|
||||
assert "'-I/spa ced/include'" in commands.get_cflags()
|
||||
|
||||
|
||||
@pytest.mark.skipif(os.name != "posix", reason="Unix link flags only")
|
||||
def test_ldflags_other_unix(monkeypatch):
|
||||
monkeypatch.syspath_prepend(str(MAIN_DIR))
|
||||
commands = importlib.import_module("pybind11.commands")
|
||||
monkeypatch.setattr(sys, "platform", "freebsd14")
|
||||
monkeypatch.setattr(commands, "_config", lambda name: "") # noqa: ARG005
|
||||
out = commands.get_ldflags()
|
||||
assert "-shared" in out
|
||||
assert "-fPIC" in out
|
||||
|
||||
|
||||
def test_cli_file():
|
||||
out = run_command_line("--file", "example.cpp").rstrip()
|
||||
ext_suffix = sysconfig.get_config_var("EXT_SUFFIX")
|
||||
assert "-std=c++17" in out
|
||||
assert out.index("-std=c++17") < out.index("example.cpp")
|
||||
assert out.endswith(f"-o example{ext_suffix}")
|
||||
if sys.platform.startswith(("linux", "darwin")):
|
||||
assert out.index("example.cpp") < out.index("-shared")
|
||||
|
||||
|
||||
def test_cli_file_embed():
|
||||
out = run_command_line("--file", "example.cpp", "--embed").rstrip()
|
||||
assert out.endswith("-o example")
|
||||
|
||||
Reference in New Issue
Block a user