[DO-1345] fixed windows packages (!16)

Reviewed-on: https://git.avroid.tech/Conan/conan_build/pulls/16
Co-authored-by: aleksandr.vodyanov <aleksandr.vodyanov@avroid.team>
Co-committed-by: aleksandr.vodyanov <aleksandr.vodyanov@avroid.team>
This commit is contained in:
aleksandr.vodyanov
2025-02-25 13:53:43 +03:00
committed by Aleksandr Vodyanov
parent 3759e1163f
commit a82e89a1bc
46 changed files with 679 additions and 197 deletions

View File

@@ -0,0 +1,6 @@
sources:
"cci.latest":
url:
- "https://nexus.avroid.tech/repository/devops-raw-proxy-github/msys2/msys2-installer/releases/download/2023-10-26/msys2-base-x86_64-20231026.tar.xz"
- "https://nexus.avroid.tech/repository/devops-raw-proxy-sourceforge_net/projects/msys2/files/Base/x86_64/msys2-base-x86_64-20231026.tar.xz"
sha256: "fa75120560563a311241c05882016978bd35612692c7f0d39815a27837bff27d"

View File

@@ -0,0 +1,196 @@
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration, ConanException
from conan.tools.files import chdir, get, replace_in_file, copy
from conan.tools.layout import basic_layout
import fnmatch
import os
import shutil
import subprocess
import errno
import ctypes
required_conan_version = ">=1.47.0"
class lock:
def __init__(self):
self.handle = ctypes.windll.kernel32.CreateMutexA(None, 0, "Global\\ConanMSYS2".encode())
if not self.handle:
raise ctypes.WinError()
def __enter__(self):
status = ctypes.windll.kernel32.WaitForSingleObject(self.handle, 0xFFFFFFFF)
if status not in [0, 0x80]:
raise ctypes.WinError()
def __exit__(self, exc_type, exc_val, exc_tb):
status = ctypes.windll.kernel32.ReleaseMutex(self.handle)
if not status:
raise ctypes.WinError()
def close(self):
ctypes.windll.kernel32.CloseHandle(self.handle)
__del__ = close
class MSYS2Conan(ConanFile):
name = "msys2"
description = "MSYS2 is a software distro and building platform for Windows"
url = "https://github.com/conan-io/conan-center-index"
homepage = "http://www.msys2.org"
license = "MSYS license"
topics = ("msys", "unix", "subsystem")
settings = "os", "arch"
# "exclude_files" "packages" "additional_packages" values are a comma separated list
options = {
"exclude_files": ["ANY"],
"packages": ["ANY"],
"additional_packages": [None, "ANY"],
"no_kill": [True, False]
}
default_options = {
"exclude_files": "*/link.exe",
"packages": "base-devel,binutils,gcc",
"additional_packages": None,
"no_kill": False,
}
short_paths = True
def layout(self):
basic_layout(self, src_folder="src")
def package_id(self):
del self.info.options.no_kill
def validate(self):
if self.settings.os != "Windows":
raise ConanInvalidConfiguration("Only Windows supported")
if self.settings.arch != "x86_64":
raise ConanInvalidConfiguration("Only Windows x64 supported")
def source(self):
get(self, **self.conan_data["sources"][self.version],
destination=self.source_folder, strip_root=False) # Preserve tarball root dir (msys64/)
def _update_pacman(self):
with chdir(self, os.path.join(self._msys_dir, "usr", "bin")):
try:
self._kill_pacman()
# https://www.msys2.org/docs/ci/
self.run('bash -l -c "pacman --debug --noconfirm --ask 20 -Syuu"') # Core update (in case any core packages are outdated)
self._kill_pacman()
self.run('bash -l -c "pacman --debug --noconfirm --ask 20 -Syuu"') # Normal update
self._kill_pacman()
self.run('bash -l -c "pacman --debug -Rc dash --noconfirm"')
except ConanException:
self.run('bash -l -c "cat /var/log/pacman.log || echo nolog"')
self._kill_pacman()
raise
# https://github.com/msys2/MSYS2-packages/issues/1966
def _kill_pacman(self):
if self.options.no_kill:
return
if (self.settings.os == "Windows"):
taskkill_exe = os.path.join(os.environ.get('SystemRoot'), 'system32', 'taskkill.exe')
log_out = True
if log_out:
out = subprocess.PIPE
err = subprocess.STDOUT
else:
out = open(os.devnull, 'w', encoding='UTF-8')
err = subprocess.PIPE
if os.path.exists(taskkill_exe):
taskkill_cmds = [
f"{taskkill_exe} /f /t /im pacman.exe",
f"{taskkill_exe} /f /im gpg-agent.exe",
f"{taskkill_exe} /f /im dirmngr.exe",
f'{taskkill_exe} /fi "MODULES eq msys-2.0.dll"',
]
for taskkill_cmd in taskkill_cmds:
try:
proc = subprocess.Popen(taskkill_cmd, stdout=out, stderr=err, bufsize=1)
proc.wait()
except OSError as e:
if e.errno == errno.ENOENT:
raise ConanException("Cannot kill pacman") from e
@property
def _msys_dir(self):
subdir = "msys64" # top-level directoy in tarball
return os.path.join(self.source_folder, subdir)
def build(self):
with lock():
self._do_build()
def _do_build(self):
packages = []
if self.options.packages:
packages.extend(str(self.options.packages).split(","))
if self.options.additional_packages:
packages.extend(str(self.options.additional_packages).split(","))
self._update_pacman()
with chdir(self, os.path.join(self._msys_dir, "usr", "bin")):
for package in packages:
self.run(f'bash -l -c "pacman -S {package} --noconfirm"')
for package in ['pkgconf']:
if self.run(f'bash -l -c "pacman -Qq {package}"', ignore_errors=True, quiet=True) == 0:
self.run(f'bash -l -c "pacman -Rs -d -d {package} --noconfirm"')
self._kill_pacman()
# create /tmp dir in order to avoid
# bash.exe: warning: could not find /tmp, please create!
tmp_dir = os.path.join(self._msys_dir, 'tmp')
if not os.path.isdir(tmp_dir):
os.makedirs(tmp_dir)
tmp_name = os.path.join(tmp_dir, 'dummy')
with open(tmp_name, 'a', encoding='UTF-8'):
os.utime(tmp_name, None)
# Prepend the PKG_CONFIG_PATH environment variable with an eventual PKG_CONFIG_PATH environment variable
# Note: this is no longer needed when we exclusively support Conan 2 integrations
replace_in_file(self, os.path.join(self._msys_dir, "etc", "profile"),
'PKG_CONFIG_PATH="', 'PKG_CONFIG_PATH="${PKG_CONFIG_PATH:+${PKG_CONFIG_PATH}:}')
def package(self):
excludes = None
if self.options.exclude_files:
excludes = tuple(str(self.options.exclude_files).split(","))
for exclude in excludes:
for root, _, filenames in os.walk(self._msys_dir):
for filename in filenames:
fullname = os.path.join(root, filename)
if fnmatch.fnmatch(fullname, exclude):
os.unlink(fullname)
# See https://github.com/conan-io/conan-center-index/blob/master/docs/error_knowledge_base.md#kb-h013-default-package-layout
copy(self, "*", dst=os.path.join(self.package_folder, "bin", "msys64"), src=self._msys_dir, excludes=excludes)
shutil.copytree(os.path.join(self._msys_dir, "usr", "share", "licenses"),
os.path.join(self.package_folder, "licenses"))
def package_info(self):
self.cpp_info.libdirs = []
self.cpp_info.includedirs = []
msys_root = os.path.join(self.package_folder, "bin", "msys64")
msys_bin = os.path.join(msys_root, "usr", "bin")
self.cpp_info.bindirs.append(msys_bin)
self.buildenv_info.define_path("MSYS_ROOT", msys_root)
self.buildenv_info.define_path("MSYS_BIN", msys_bin)
self.conf_info.define("tools.microsoft.bash:subsystem", "msys2")
self.conf_info.define("tools.microsoft.bash:path", os.path.join(msys_bin, "bash.exe"))
# conan v1 specific stuff
self.env_info.MSYS_ROOT = msys_root
self.env_info.MSYS_BIN = msys_bin
self.env_info.path.append(msys_bin)

View File

@@ -0,0 +1,34 @@
from conan import ConanFile
from conan.tools.env import Environment
from io import StringIO
class TestPackageConan(ConanFile):
settings = "os", "arch"
generators = "VirtualBuildEnv"
test_type = "explicit"
def build_requirements(self):
self.tool_requires(self.tested_reference_str)
@property
def _secret_value(self):
return "SECRET_CONAN_PKG_VARIABLE"
def generate(self):
env = Environment()
env.define("PKG_CONFIG_PATH", self._secret_value)
envvars = env.vars(self)
envvars.save_script("conanbuildenv_pkg_config_path")
def build(self):
pass # nothing to do, skip hook warning
def test(self):
self.run('bash.exe -c ^"make --version^"')
self.run('bash.exe -c ^"! test -f /bin/link^"')
self.run('bash.exe -c ^"! test -f /usr/bin/link^"')
output = StringIO()
self.run('bash.exe -c "echo $PKG_CONFIG_PATH"', output)
assert self._secret_value in output.getvalue()

View File

@@ -0,0 +1,28 @@
from conans import ConanFile, tools
from conans.errors import ConanException
from io import StringIO
class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
def build(self):
pass # nothing to do, skip hook warning
def test(self):
bash = tools.which("bash.exe")
if bash:
self.output.info("using bash.exe from: " + bash)
else:
raise ConanException("No instance of bash.exe could be found on %PATH%")
self.run('bash.exe -c ^"make --version^"')
self.run('bash.exe -c ^"! test -f /bin/link^"')
self.run('bash.exe -c ^"! test -f /usr/bin/link^"')
secret_value = "SECRET_CONAN_PKG_VARIABLE"
with tools.environment_append({"PKG_CONFIG_PATH": secret_value}):
output = StringIO()
self.run('bash.exe -c "echo $PKG_CONFIG_PATH"', output=output)
assert secret_value in output.getvalue()

3
recipes/msys2/config.yml Normal file
View File

@@ -0,0 +1,3 @@
versions:
"cci.latest":
folder: "all"