Repository: conan-io/conan
Pull request #16647 (2024-07-10 13:55:29)

Remove `ld` and `ar` from `tools.build:compiler_executables`
Changelog: Fix: Remove unsupported `ld` and `ar` entries from `tools.build:compiler_executables`, they had no effect in every Conan integration
Docs: Omit


Normally, people use the environment variables provided by each toolchain to introduce `ar` and `ld`. Additionally, no Conan toolchain implements either `ar` or `ld` from `tools.build:compiler_executables`. Therefore, I believe it is better to remove these variables to avoid future problems.

Close: #16517


Patch:
diff --git a/conan/tools/cmake/layout.py b/conan/tools/cmake/layout.py
index dad6ce312..fbff89c20 100644
--- a/conan/tools/cmake/layout.py
+++ b/conan/tools/cmake/layout.py
@@ -94,9 +94,11 @@ def get_build_folder_custom_vars(conanfile):
                     tmp = "{}_{}".format(var, value)
         elif group == "self":
             tmp = getattr(conanfile, var, None)
+        elif group == "const":
+            tmp = var
         else:
             raise ConanException("Invalid 'tools.cmake.cmake_layout:build_folder_vars' value, it has"
-                                 " to start with 'settings.' or 'options.': {}".format(s))
+                                 f" to start with 'settings.', 'options.', 'self.' or 'const.': {s}")
         if tmp:
             ret.append(tmp.lower())
 
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index 0d6585718..425e62b2a 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -724,7 +724,7 @@ class ExtraFlagsBlock(Block):
         {% if defines %}
         {% if config %}
         {% for define in defines %}
-        add_compile_definitions($<$<CONFIG:{{config}}>:"{{ define }}">)
+        add_compile_definitions("$<$<CONFIG:{{config}}>:{{ define }}>")
         {% endfor %}
         {% else %}
         add_compile_definitions({% for define in defines %} "{{ define }}"{% endfor %})
diff --git a/conan/tools/gnu/gnutoolchain.py b/conan/tools/gnu/gnutoolchain.py
index 95c32129e..9848e18fc 100644
--- a/conan/tools/gnu/gnutoolchain.py
+++ b/conan/tools/gnu/gnutoolchain.py
@@ -123,15 +123,13 @@ class GnuToolchain:
         if is_msvc(self._conanfile):
             extra_env_vars = {"CC": "cl -nologo",
                               "CXX": "cl -nologo",
-                              "LD": "link -nologo",
-                              "AR": "lib",
                               "NM": "dumpbin -symbols",
                               "OBJDUMP": ":",
                               "RANLIB": ":",
                               "STRIP": ":"}
         # Configuration map
         compilers_mapping = {"c": "CC", "cpp": "CXX", "cuda": "NVCC", "fortran": "FC",
-                             "rc": "RC", "ld": "LD", "ar": "AR", "nm": "NM", "ranlib": "RANLIB",
+                             "rc": "RC", "nm": "NM", "ranlib": "RANLIB",
                              "objdump": "OBJDUMP", "strip": "STRIP"}
         # Compiler definitions by conf
         compilers_by_conf = self._conanfile.conf.get("tools.build:compiler_executables", default={},
diff --git a/conans/model/conf.py b/conans/model/conf.py
index 1a36d24a5..e56541cfa 100644
--- a/conans/model/conf.py
+++ b/conans/model/conf.py
@@ -117,7 +117,7 @@ BUILT_IN_CONFS = {
     "tools.apple:enable_visibility": "(boolean) Enable/Disable Visibility Apple Clang flags",
     "tools.env.virtualenv:powershell": "If it is set to True it will generate powershell launchers if os=Windows",
     # Compilers/Flags configurations
-    "tools.build:compiler_executables": "Defines a Python dict-like with the compilers path to be used. Allowed keys {'c', 'cpp', 'cuda', 'objc', 'objcxx', 'rc', 'fortran', 'asm', 'hip', 'ispc', 'ld', 'ar'}",
+    "tools.build:compiler_executables": "Defines a Python dict-like with the compilers path to be used. Allowed keys {'c', 'cpp', 'cuda', 'objc', 'objcxx', 'rc', 'fortran', 'asm', 'hip', 'ispc'}",
     "tools.build:cxxflags": "List of extra CXX flags used by different toolchains like CMakeToolchain, AutotoolsToolchain and MesonToolchain",
     "tools.build:cflags": "List of extra C flags used by different toolchains like CMakeToolchain, AutotoolsToolchain and MesonToolchain",
     "tools.build:defines": "List of extra definition flags used by different toolchains like CMakeToolchain, AutotoolsToolchain and MesonToolchain",


Test patch:
diff --git a/test/functional/toolchains/cmake/test_cmake_toolchain.py b/test/functional/toolchains/cmake/test_cmake_toolchain.py
index acd6c5ee1..b64c5c791 100644
--- a/test/functional/toolchains/cmake/test_cmake_toolchain.py
+++ b/test/functional/toolchains/cmake/test_cmake_toolchain.py
@@ -1913,3 +1913,106 @@ def test_cmake_toolchain_cxxflags_multi_config():
     assert 'DEFINE conan_test_answer=123' in c.out
     assert 'other=' not in c.out
     assert "CPLUSPLUS: __cplusplus19" in c.out
+
+
+@pytest.mark.tool("ninja")
+@pytest.mark.tool("cmake", "3.23")
+def test_cmake_toolchain_ninja_multi_config():
+    c = TestClient()
+    profile_release = textwrap.dedent(r"""
+        include(default)
+        [conf]
+        tools.cmake.cmaketoolchain:generator=Ninja Multi-Config
+        tools.build:defines=["conan_test_answer=42", "conan_test_other=24"]
+        """)
+    profile_debug = textwrap.dedent(r"""
+        include(default)
+        [settings]
+        build_type=Debug
+        [conf]
+        tools.cmake.cmaketoolchain:generator=Ninja Multi-Config
+        tools.build:defines=["conan_test_answer=123"]
+        """)
+    profile_relwithdebinfo = textwrap.dedent(r"""
+        include(default)
+        [settings]
+        build_type=RelWithDebInfo
+        [conf]
+        tools.cmake.cmaketoolchain:generator=Ninja Multi-Config
+        tools.build:defines=["conan_test_answer=456", "conan_test_other=abc", 'conan_test_complex="1 2"']
+        """)
+
+    conanfile = textwrap.dedent(r'''
+        from conan import ConanFile
+        from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
+
+        class Test(ConanFile):
+            exports_sources = "CMakeLists.txt", "src/*"
+            settings = "os", "compiler", "arch", "build_type"
+            generators = "CMakeToolchain"
+
+            def layout(self):
+                cmake_layout(self)
+
+            def build(self):
+                cmake = CMake(self)
+                cmake.configure()
+                cmake.build()
+        ''')
+
+    main = textwrap.dedent(r"""
+        #include <iostream>
+        #include <stdio.h>
+
+        #define STR(x)   #x
+        #define SHOW_DEFINE(x) printf("DEFINE %s=%s!\n", #x, STR(x))
+
+        int main() {
+            SHOW_DEFINE(conan_test_answer);
+            #ifdef conan_test_other
+            SHOW_DEFINE(conan_test_other);
+            #endif
+            #ifdef conan_test_complex
+            SHOW_DEFINE(conan_test_complex);
+            #endif
+        }
+        """)
+
+    cmakelists = textwrap.dedent("""
+        cmake_minimum_required(VERSION 3.15)
+        project(Test CXX)
+        add_executable(example src/main.cpp)
+        """)
+
+    c.save({"conanfile.py": conanfile,
+            "profile_release": profile_release,
+            "profile_debug": profile_debug,
+            "profile_relwithdebinfo": profile_relwithdebinfo,
+            "src/main.cpp": main,
+            "CMakeLists.txt": cmakelists})
+    c.run("install . -pr=./profile_release")
+    c.run("install . -pr=./profile_debug")
+    c.run("install . -pr=./profile_relwithdebinfo")
+
+    with c.chdir("build"):
+        env = r".\generators\conanbuild.bat &&" if platform.system() == "Windows" else ""
+        c.run_command(f"{env} cmake .. -G \"Ninja Multi-Config\" "
+                      "-DCMAKE_TOOLCHAIN_FILE=generators/conan_toolchain.cmake")
+        c.run_command(f"{env} cmake --build . --config Release")
+        c.run_command(f"{env} cmake --build . --config Debug")
+        c.run_command(f"{env} cmake --build . --config RelWithDebInfo")
+
+    c.run_command(os.sep.join([".", "build", "Release", "example"]))
+    assert 'DEFINE conan_test_answer=42!' in c.out
+    assert 'DEFINE conan_test_other=24!' in c.out
+    assert 'complex=' not in c.out
+
+    c.run_command(os.sep.join([".", "build", "Debug", "example"]))
+    assert 'DEFINE conan_test_answer=123' in c.out
+    assert 'other=' not in c.out
+    assert 'complex=' not in c.out
+
+    c.run_command(os.sep.join([".", "build", "RelWithDebInfo", "example"]))
+    assert 'DEFINE conan_test_answer=456!' in c.out
+    assert 'DEFINE conan_test_other=abc!' in c.out
+    assert 'DEFINE conan_test_complex="1 2"!' in c.out
diff --git a/test/integration/toolchains/cmake/test_cmaketoolchain.py b/test/integration/toolchains/cmake/test_cmaketoolchain.py
index dee27284e..38ac9049b 100644
--- a/test/integration/toolchains/cmake/test_cmaketoolchain.py
+++ b/test/integration/toolchains/cmake/test_cmaketoolchain.py
@@ -1278,6 +1278,32 @@ def test_build_folder_vars_self_name_version():
     assert "conan-windows-pkg-0.1-debug" in presets
 
 
+def test_build_folder_vars_constants_user():
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conan.tools.cmake import cmake_layout
+
+        class Conan(ConanFile):
+            name = "dep"
+            version = "0.1"
+            settings = "os", "build_type"
+            generators = "CMakeToolchain"
+
+            def layout(self):
+                cmake_layout(self)
+        """)
+    c.save({"conanfile.py": conanfile})
+    conf = "tools.cmake.cmake_layout:build_folder_vars='[\"const.myvalue\"]'"
+    settings = " -s os=FreeBSD -s arch=armv8 -s build_type=Debug"
+    c.run("install . -c={} {}".format(conf, settings))
+    assert "cmake --preset conan-myvalue-debug" in c.out
+    assert os.path.exists(os.path.join(c.current_folder, "build", "myvalue", "Debug"))
+    presets = load(os.path.join(c.current_folder,
+                                "build/myvalue/Debug/generators/CMakePresets.json"))
+    assert "conan-myvalue-debug" in presets
+
+
 def test_extra_flags():
     client = TestClient()
     conanfile = textwrap.dedent("""
diff --git a/test/integration/toolchains/gnu/test_gnutoolchain.py b/test/integration/toolchains/gnu/test_gnutoolchain.py
index 653599ae6..d35d45b04 100644
--- a/test/integration/toolchains/gnu/test_gnutoolchain.py
+++ b/test/integration/toolchains/gnu/test_gnutoolchain.py
@@ -381,8 +381,6 @@ def test_msvc_profile_defaults():
             # Default values and conf ones
             assert r'set "CC=clang"' in content  # conf value has precedence
             assert r'set "CXX=clang++"' in content  # conf value has precedence
-            assert 'set "LD=link -nologo"' in content
-            assert r'set "AR=lib"' in content
             assert 'set "NM=dumpbin -symbols"' in content
             assert 'set "OBJDUMP=:"' in content
             assert 'set "RANLIB=:"' in content
@@ -412,8 +410,6 @@ def test_msvc_profile_defaults():
             # Prepending compiler wrappers
             tc.extra_env.prepend("CC", "compile")
             tc.extra_env.prepend("CXX", "compile")
-            tc.extra_env.prepend("AR", "ar-lib")
-            tc.extra_env.append("LD", "-fixed")
             tc.extra_env.define("OBJDUMP", "other-value")
             tc.extra_env.unset("RANLIB")
             tc.generate()
@@ -424,8 +420,6 @@ def test_msvc_profile_defaults():
             # Default values
             assert r'set "CC=compile clang"' in content
             assert r'set "CXX=compile clang++"' in content
-            assert 'set "LD=link -nologo -fixed"' in content  # appended new value
-            assert r'set "AR=ar-lib lib"' in content
             assert 'set "NM=dumpbin -symbols"' in content
             assert 'set "OBJDUMP=other-value"' in content  # redefined
             assert 'set "RANLIB=:"' not in content  # removed