Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

msys2: conan v2 support #12715

Merged
merged 4 commits into from
Sep 9, 2022
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
84 changes: 49 additions & 35 deletions recipes/msys2/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from conans import ConanFile, tools
from conans.errors import ConanInvalidConfiguration, ConanException
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration, ConanException
from conan.tools.files import chdir, get, replace_in_file
import fnmatch
import os
import shutil
Expand All @@ -8,12 +9,14 @@

try:
import ctypes
from ctypes import wintypes
except ImportError:
pass
except ValueError:
pass

required_conan_version = ">=1.47.0"


class lock:
def __init__(self):
self.handle = ctypes.windll.kernel32.CreateMutexA(None, 0, "Global\\ConanMSYS2".encode())
Expand Down Expand Up @@ -42,31 +45,39 @@ class MSYS2Conan(ConanFile):
url = "https://github.com/conan-io/conan-center-index"
homepage = "http://www.msys2.org"
license = "MSYS license"
topics = ("conan", "msys", "unix", "subsystem")
short_paths = True
topics = ("msys", "unix", "subsystem")

settings = "os", "arch", "compiler", "build_type"
# "exclude_files" "packages" "additional_packages" values are a comma separated list
options = {
"exclude_files": "ANY",
"packages": "ANY",
"additional_packages": "ANY"
"exclude_files": ["ANY"],
"packages": ["ANY"],
"additional_packages": ["ANY"],
}
default_options = {
"exclude_files": "*/link.exe",
"packages": "base-devel,binutils,gcc",
"additional_packages": None
"additional_packages": None,
}
settings = "os", "arch"

short_paths = True

def package_id(self):
del self.info.settings.compiler
del self.info.settings.build_type

def validate(self):
if self.settings.os != "Windows":
if self.info.settings.os != "Windows":
raise ConanInvalidConfiguration("Only Windows supported")
if self.settings.arch != "x86_64":
if self.info.settings.arch != "x86_64":
raise ConanInvalidConfiguration("Only Windows x64 supported")

def source(self):
# sources are different per configuration - do download in build
pass

def _update_pacman(self):
with tools.chdir(os.path.join(self._msys_dir, "usr", "bin")):
with chdir(self, os.path.join(self._msys_dir, "usr", "bin")):
try:
self._kill_pacman()

Expand Down Expand Up @@ -95,10 +106,12 @@ def _kill_pacman(self):
err = subprocess.PIPE

if os.path.exists(taskkill_exe):
taskkill_cmds = [taskkill_exe + " /f /t /im pacman.exe",
taskkill_exe + " /f /im gpg-agent.exe",
taskkill_exe + " /f /im dirmngr.exe",
taskkill_exe + ' /fi "MODULES eq msys-2.0.dll"']
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)
Expand All @@ -112,13 +125,9 @@ def _msys_dir(self):
subdir = "msys64"
return os.path.join(self.package_folder, "bin", subdir)

def source(self):
# sources are different per configuration - do download in build
pass

def build(self):
tools.get(**self.conan_data["sources"][self.version],
destination=os.path.join(self.package_folder, "bin"))
get(self, **self.conan_data["sources"][self.version],
destination=os.path.join(self.package_folder, "bin"))
with lock():
self._do_build()

Expand All @@ -131,11 +140,11 @@ def _do_build(self):

self._update_pacman()

with tools.chdir(os.path.join(self._msys_dir, "usr", "bin")):
with chdir(self, os.path.join(self._msys_dir, "usr", "bin")):
for package in packages:
self.run('bash -l -c "pacman -S %s --noconfirm"' % package)
self.run(f'bash -l -c "pacman -S {package} --noconfirm"')
for package in ['pkgconf']:
self.run('bash -l -c "pacman -Rs -d -d $(pacman -Qsq %s) --noconfirm"' % package)
self.run(f'bash -l -c "pacman -Rs -d -d $(pacman -Qsq {package}) --noconfirm"')

self._kill_pacman()

Expand All @@ -149,7 +158,7 @@ def _do_build(self):
os.utime(tmp_name, None)

# Prepend the PKG_CONFIG_PATH environment variable with an eventual PKG_CONFIG_PATH environment variable
tools.replace_in_file(os.path.join(self._msys_dir, "etc", "profile"),
replace_in_file(self, os.path.join(self._msys_dir, "etc", "profile"),
'PKG_CONFIG_PATH="', 'PKG_CONFIG_PATH="$PKG_CONFIG_PATH:')

def package(self):
Expand All @@ -169,18 +178,23 @@ def package(self):
def package_info(self):
self.cpp_info.libdirs = []
self.cpp_info.includedirs = []
self.cpp_info.resdirs = []

msys_root = self._msys_dir
msys_bin = os.path.join(msys_root, "usr", "bin")
self.cpp_info.bindirs.append(msys_bin)

self.output.info("Creating MSYS_ROOT env var : %s" % msys_root)
self.env_info.MSYS_ROOT = msys_root
self.output.info(f"Creating MSYS_ROOT env var : {msys_root}")
self.buildenv_info.define_path("MSYS_ROOT", msys_root)

self.output.info("Creating MSYS_BIN env var : %s" % msys_bin)
self.env_info.MSYS_BIN = msys_bin
self.output.info(f"Creating MSYS_BIN env var : {msys_bin}")
self.buildenv_info.define_path("MSYS_BIN", msys_bin)

self.conf_info.define("tools.microsoft.bash:subsystem", "msys2")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!!!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also experimenting with changing this recipe and using the buildenv_info, but I noticed that I needed to fix the subsystem.py for that to work correctly in consuming projects. See PR conan-io/conan#11981 and conan-io/conan#11980

I also still needed to keep on using the old env_info otherwise to much of my dependencies such as libffi needed to be overhauled. By defining them both I only needed to overhaul automake and autoconf. See: master...Ultimaker:conan-center-index:modernize_autoconf for a work in progress

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also still needed to keep on using the old env_info otherwise to much of my dependencies such as libffi needed to be overhauled. By defining them both I only needed to overhaul automake and autoconf. See: master...Ultimaker:conan-center-index:modernize_autoconf for a work in progress

related to conan-io/conan#11974 (comment)?

Copy link
Contributor Author

@SpaceIm SpaceIm Aug 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact is that env_info must be kept for the moment in package_info() of CCI recipes, along buildenv_info, to achieve v1/v2 cross-compatibility. Because conan v1 recipes don't use at all buildenv_info of tool_requires, and even some conan v2 recipes (it depends on user configuration or if VirtualBuildEnv is explicitly used, see conan-io/conan#11974 (comment) again).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx, will keep that in mind. You're updating those recipes at an amazing speed. I think that when I'm finally finished with my struggle getting CPython and Qt to compile on Windows, my change aren't needed anymore 😉.

self.conf_info.define("tools.microsoft.bash:path", os.path.join(msys_bin, "bash.exe"))

self.output.info("Appending PATH env var with : " + msys_bin)
# conan v1 specific stuff
self.env_info.MSYS_ROOT = msys_root
self.env_info.MSYS_BIN = msys_bin
self.output.info(f"Appending PATH env var with : {msys_bin}")
self.env_info.path.append(msys_bin)

self.conf_info["tools.microsoft.bash:subsystem"] = "msys2"
self.conf_info["tools.microsoft.bash:path"] = os.path.join(msys_bin, "bash.exe")
42 changes: 25 additions & 17 deletions recipes/msys2/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
from conans import ConanFile, tools
from conans.errors import ConanException
from conan import ConanFile
from conan.tools.env import Environment
from io import StringIO

class TestPackage(ConanFile):


class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
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):
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)
print(output.getvalue())
assert secret_value in output.getvalue()
output = StringIO()
self.run('bash.exe -c "echo $PKG_CONFIG_PATH"', output=output)
print(output.getvalue())
assert self._secret_value in output.getvalue()
29 changes: 29 additions & 0 deletions recipes/msys2/all/test_v1_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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)
print(output.getvalue())
assert secret_value in output.getvalue()