Skip to content

Commit

Permalink
[fix] CONAN_TOOLCHAIN_ARGS_FILE as configuration file (#9225)
Browse files Browse the repository at this point in the history
* Added ConfigParser as mechanism to save toolchain-file arguments

* Fixed tests and pruning None values from toolchain content

* Optimized imports

* Added unittests and changed save/load mechanism

* Added double-check to load a non-existing/incorrect conanbuild.conf

* Ensuring toolchains are loading the conanbuild file

* Changing Bazel tests
  • Loading branch information
franramirez688 committed Jul 12, 2021
1 parent 9c43bd7 commit b61f761
Show file tree
Hide file tree
Showing 17 changed files with 168 additions and 108 deletions.
3 changes: 2 additions & 1 deletion conan/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
CONAN_TOOLCHAIN_ARGS_FILE = "conanbuild.json"
CONAN_TOOLCHAIN_ARGS_FILE = "conanbuild.conf"
CONAN_TOOLCHAIN_ARGS_SECTION = "toolchain"
15 changes: 6 additions & 9 deletions conan/tools/cmake/cmake.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import json
import os
import os
import platform

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conan.tools.cmake.utils import is_multi_configuration
from conan.tools.files import load_toolchain_args
from conan.tools.gnu.make import make_jobs_cmd_line_arg
from conan.tools.meson.meson import ninja_jobs_cmd_line_arg
from conan.tools.microsoft.msbuild import msbuild_verbosity_cmd_line_arg, \
Expand All @@ -12,7 +12,7 @@
from conans.client.tools.files import chdir
from conans.client.tools.oss import cpu_count, args_to_string
from conans.errors import ConanException
from conans.util.files import mkdir, load
from conans.util.files import mkdir


def _validate_recipe(conanfile):
Expand Down Expand Up @@ -66,13 +66,10 @@ def __init__(self, conanfile, parallel=True):
# Store a reference to useful data
self._conanfile = conanfile
self._parallel = parallel
self._generator = None

args_file = os.path.join(self._conanfile.generators_folder, CONAN_TOOLCHAIN_ARGS_FILE)
if os.path.exists(args_file):
json_args = json.loads(load(args_file))
self._generator = json_args.get("cmake_generator")
self._toolchain_file = json_args.get("cmake_toolchain_file")
toolchain_file_content = load_toolchain_args(self._conanfile.generators_folder)
self._generator = toolchain_file_content.get("cmake_generator")
self._toolchain_file = toolchain_file_content.get("cmake_toolchain_file")

self._cmake_program = "cmake" # Path to CMake should be handled by environment

Expand Down
5 changes: 2 additions & 3 deletions conan/tools/cmake/toolchain.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import json
import os
import re
import textwrap
Expand All @@ -7,10 +6,10 @@
import six
from jinja2 import Template

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conan.tools._check_build_profile import check_using_build_profile
from conan.tools._compilers import architecture_flag, use_win_mingw
from conan.tools.cmake.utils import is_multi_configuration, get_file_name
from conan.tools.files import save_toolchain_args
from conan.tools.microsoft import VCVars
from conan.tools.microsoft.visual import vs_ide_version
from conans.errors import ConanException
Expand Down Expand Up @@ -741,7 +740,7 @@ def _writebuild(self, toolchain_file):
result["cmake_toolchain_file"] = toolchain_file or self.filename

if result:
save(CONAN_TOOLCHAIN_ARGS_FILE, json.dumps(result))
save_toolchain_args(result)

def _get_generator(self, recipe_generator):
# Returns the name of the generator to be used by CMake
Expand Down
2 changes: 1 addition & 1 deletion conan/tools/files/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from conan.tools.files.files import load, save, mkdir, ftp_download, download, get, rename, \
load_build_json, save_build_json
load_toolchain_args, save_toolchain_args
from conan.tools.files.patches import patch, apply_conandata_patches
from conan.tools.files.cpp_package import CppPackage
47 changes: 37 additions & 10 deletions conan/tools/files/files.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import configparser
import errno
import json
import os
import platform
import subprocess

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE, CONAN_TOOLCHAIN_ARGS_SECTION
from conans.client.downloaders.download import run_downloader
from conans.client.tools.files import unzip, which
from conans.errors import ConanException
Expand Down Expand Up @@ -185,13 +185,40 @@ def rename(conanfile, src, dst):
raise ConanException("rename {} to {} failed: {}".format(src, dst, err))


def load_build_json(conanfile):
path = os.path.join(conanfile.generators_folder, CONAN_TOOLCHAIN_ARGS_FILE)
contents = load(conanfile, path)
data = json.loads(contents)
return data
def load_toolchain_args(generators_folder=None):
"""
Helper function to load the content of any CONAN_TOOLCHAIN_ARGS_FILE
:param generators_folder: `str` folder where is located the CONAN_TOOLCHAIN_ARGS_FILE.
:return: <class 'configparser.SectionProxy'>
"""
args_file = os.path.join(generators_folder, CONAN_TOOLCHAIN_ARGS_FILE) if generators_folder \
else CONAN_TOOLCHAIN_ARGS_FILE
toolchain_config = configparser.ConfigParser()
toolchain_file = toolchain_config.read(args_file)
if not toolchain_file:
raise ConanException("The file %s does not exist. Please, make sure that it was not"
" generated in another folder." % args_file)
try:
return toolchain_config[CONAN_TOOLCHAIN_ARGS_SECTION]
except KeyError:
raise ConanException("The primary section [%s] does not exist in the file %s. Please, add it"
" as the default one of all your configuration variables." %
(CONAN_TOOLCHAIN_ARGS_SECTION, args_file))


def save_build_json(conanfile, contents):
path = os.path.join(conanfile.generators_folder, CONAN_TOOLCHAIN_ARGS_FILE)
save(conanfile, path, json.dumps(contents))
def save_toolchain_args(content, generators_folder=None):
"""
Helper function to save the content into the CONAN_TOOLCHAIN_ARGS_FILE
:param content: `dict` all the information to be saved into the toolchain file.
:param generators_folder: `str` folder where is located the CONAN_TOOLCHAIN_ARGS_FILE
"""
# Let's prune None values
content_ = {k: v for k, v in content.items() if v is not None}
args_file = os.path.join(generators_folder, CONAN_TOOLCHAIN_ARGS_FILE) if generators_folder \
else CONAN_TOOLCHAIN_ARGS_FILE
toolchain_config = configparser.ConfigParser()
toolchain_config[CONAN_TOOLCHAIN_ARGS_SECTION] = content_
with open(args_file, "w") as f:
toolchain_config.write(f)
16 changes: 4 additions & 12 deletions conan/tools/gnu/autotools.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
import json
import os
import platform

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conan.tools._compilers import use_win_mingw
from conan.tools.files import load_toolchain_args
from conan.tools.gnu.make import make_jobs_cmd_line_arg
from conan.tools.microsoft import unix_path
from conans.client.build import join_arguments
from conans.util.files import load


class Autotools(object):

def __init__(self, conanfile):
self._conanfile = conanfile

args_path = os.path.join(conanfile.generators_folder, CONAN_TOOLCHAIN_ARGS_FILE)
if os.path.isfile(args_path):
args = json.loads(load(args_path))
self._configure_args = args.get("configure_args")
self._make_args = args.get("make_args")
toolchain_file_content = load_toolchain_args(self._conanfile.generators_folder)
self._configure_args = toolchain_file_content.get("configure_args")
self._make_args = toolchain_file_content.get("make_args")

def configure(self):
"""
Expand Down
7 changes: 2 additions & 5 deletions conan/tools/gnu/autotoolstoolchain.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import json

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conan.tools._check_build_profile import check_using_build_profile
from conan.tools._compilers import architecture_flag, build_type_flags, cppstd_flag
from conan.tools.apple.apple import apple_min_version_flag, to_apple_arch, \
apple_sdk_path
from conan.tools.cross_building import cross_building, get_cross_building_settings
from conan.tools.env import Environment
from conan.tools.files import save
from conan.tools.files import save_toolchain_args
from conan.tools.gnu.get_gnu_triplet import _get_gnu_triplet
from conans.tools import args_to_string

Expand Down Expand Up @@ -168,4 +165,4 @@ def generate_args(self):
args = {"configure_args": args_to_string(configure_args),
"make_args": args_to_string(self.make_args)}

save(self._conanfile, CONAN_TOOLCHAIN_ARGS_FILE, json.dumps(args))
save_toolchain_args(args)
15 changes: 4 additions & 11 deletions conan/tools/google/bazel.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import os
import json
from conan.tools.files import load_toolchain_args

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conans.util.files import load

class Bazel(object):
def __init__(self, conanfile):
Expand Down Expand Up @@ -40,10 +37,6 @@ def build(self, args=None, label=None):
self._conanfile.run(command)

def _get_bazel_project_configuration(self):
self._bazel_config = None
self._bazelrc_path = None

if os.path.exists(CONAN_TOOLCHAIN_ARGS_FILE):
conan_toolchain_args = json.loads(load(CONAN_TOOLCHAIN_ARGS_FILE))
self._bazel_config = conan_toolchain_args.get("bazel_config", None)
self._bazelrc_path = conan_toolchain_args.get("bazelrc_path", None)
toolchain_file_content = load_toolchain_args(self._conanfile.generators_folder)
self._bazel_config = toolchain_file_content.get("bazel_config")
self._bazelrc_path = toolchain_file_content.get("bazelrc_path")
16 changes: 5 additions & 11 deletions conan/tools/google/toolchain.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import json

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conan.tools._check_build_profile import check_using_build_profile
from conans.util.files import save
from conan.tools.files import save_toolchain_args


class BazelToolchain(object):
Expand All @@ -12,10 +9,7 @@ def __init__(self, conanfile):
check_using_build_profile(self._conanfile)

def generate(self):
bazel_config = self._conanfile.conf["tools.google.bazel:config"]
bazelrc_path = self._conanfile.conf["tools.google.bazel:bazelrc_path"]

save(CONAN_TOOLCHAIN_ARGS_FILE, json.dumps({
"bazel_config": bazel_config,
"bazelrc_path": bazelrc_path
}))
save_toolchain_args({
"bazel_config": self._conanfile.conf["tools.google.bazel:config"],
"bazelrc_path": self._conanfile.conf["tools.google.bazel:bazelrc_path"]
})
5 changes: 3 additions & 2 deletions conans/test/functional/toolchains/cmake/test_ninja.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest

from conan.tools.cmake import CMakeToolchain
from conan.tools.files import load_toolchain_args
from conans.test.assets.cmake import gen_cmakelists
from conans.test.assets.genconanfile import GenConanfile
from conans.test.assets.sources import gen_function_h, gen_function_cpp
Expand Down Expand Up @@ -219,8 +220,8 @@ def test_ninja_conf():
client.save({"conanfile.py": conanfile,
"profile": profile})
client.run("install . -pr=profile")
conanbuild = client.load("conanbuild.json")
assert '"cmake_generator": "Ninja"' in conanbuild
conanbuild = load_toolchain_args(client.current_folder)
assert conanbuild["cmake_generator"] == "Ninja"
vcvars = client.load("conanvcvars.bat")
assert "2017" in vcvars

Expand Down
7 changes: 4 additions & 3 deletions conans/test/functional/toolchains/gnu/autotools/test_ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pytest

from conan.tools.files import load_toolchain_args
from conans.client.tools.apple import XCRun, to_apple_arch
from conans.test.assets.autotools import gen_makefile_am, gen_configure_ac
from conans.test.assets.sources import gen_function_cpp
Expand Down Expand Up @@ -72,6 +73,6 @@ def build(self):
client.run_command("lipo -info main")
assert "Non-fat file: main is architecture: arm64" in client.out

js = client.load("conanbuild.json")
assert '--host=aarch64-apple-ios' in js
assert '--build=x86_64-apple-darwin' in js
conanbuild = load_toolchain_args(client.current_folder)
configure_args = conanbuild["configure_args"]
assert configure_args == "'--host=aarch64-apple-ios' '--build=x86_64-apple-darwin'"
11 changes: 4 additions & 7 deletions conans/test/functional/toolchains/test_bazel_toolchain.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import textwrap

from conan.tools.files import load_toolchain_args
from conans.test.assets.genconanfile import GenConanfile
from conans.test.utils.tools import TestClient

Expand All @@ -14,10 +14,8 @@ def test_toolchain_empty_config():
client.save({"conanfile.py": conanfile})
client.run("install .")

config = json.loads(client.load("conanbuild.json"))

assert config['bazel_config'] is None
assert config['bazelrc_path'] is None
config = load_toolchain_args(client.current_folder)
assert not config


def test_toolchain_loads_config_from_profile():
Expand All @@ -39,7 +37,6 @@ def test_toolchain_loads_config_from_profile():
})
client.run("install . -pr=test_profile")

config = json.loads(client.load("conanbuild.json"))

config = load_toolchain_args(client.current_folder)
assert config['bazel_config'] == "test_config"
assert config['bazelrc_path'] == "/path/to/bazelrc"
6 changes: 3 additions & 3 deletions conans/test/functional/toolchains/test_cmake_toolchain.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import json
import os
import platform

import pytest

from conan.tools.files import load_toolchain_args
from conans.test.assets.genconanfile import GenConanfile
from conans.test.utils.tools import TestClient
from conans.util.files import save
Expand Down Expand Up @@ -61,5 +61,5 @@ def test_cmake_toolchain_custom_toolchain():
client.save({"conanfile.py": conanfile})
client.run("install .")
assert not os.path.exists(os.path.join(client.current_folder, "conan_toolchain.cmake"))
buildjson = json.loads(client.load("conanbuild.json"))
assert "mytoolchain.cmake" == buildjson["cmake_toolchain_file"]
build_content = load_toolchain_args(client.current_folder)
assert "mytoolchain.cmake" == build_content["cmake_toolchain_file"]
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

from mock import Mock

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conan.tools.files import save_toolchain_args
from conan.tools.gnu import Autotools
from conans import ConanFile
from conans.client.tools.files import save
from conans.model.conf import Conf
from conans.test.unittests.util.tools_test import RunnerMock
from conans.test.utils.mocks import MockSettings
Expand All @@ -15,10 +14,10 @@
def test_configure_arguments():
tmp = temp_folder()
os.chdir(tmp)
save(CONAN_TOOLCHAIN_ARGS_FILE, """
{"configure_args": "my_configure_args",
"make_args": "my_make_args"}
""")
save_toolchain_args({
"configure_args": "my_configure_args",
"make_args": "my_make_args"}
)
runner = RunnerMock()
conanfile = ConanFile(Mock(), runner=runner)
conanfile.settings = MockSettings({})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import json
import platform
from os import chdir

import pytest

from conan.tools import CONAN_TOOLCHAIN_ARGS_FILE
from conan.tools.files import load_toolchain_args
from conan.tools.gnu import AutotoolsToolchain
from conans.errors import ConanException
from conans.model.conf import Conf
Expand Down Expand Up @@ -45,9 +44,7 @@ def test_target_triple():
be = AutotoolsToolchain(conanfile)
be.make_args = ["foo", "var"]
be.generate_args()
with open(CONAN_TOOLCHAIN_ARGS_FILE) as f:
obj = json.load(f)

obj = load_toolchain_args()
assert "--host=x86_64-linux-gnu" in obj["configure_args"]
assert "--build=i686-solaris" in obj["configure_args"]
assert obj["make_args"].replace("'", "") == "foo var"
Expand Down Expand Up @@ -75,7 +72,7 @@ def test_cppstd():
"cppstd": "17"})
be = AutotoolsToolchain(conanfile)
env = be.environment()
assert not "-std=c++17" in env["CXXFLAGS"]
assert "-std=c++17" not in env["CXXFLAGS"]

# Using "compiler.cppstd" works
conanfile.settings = MockSettings(
Expand Down

0 comments on commit b61f761

Please sign in to comment.