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>
197 lines
7.5 KiB
Python
197 lines
7.5 KiB
Python
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)
|