Repository: conan-io/conan

Issue:
[feature] provide a more advanced autotools_layout() to the level of cmake for autotools package supporting out-of-tree build
### What is your suggestion?

autotools package support building outside of the source tree folder using the approach

cd $build
../configure && make && ...

for those autotools package supporting this mode a autotools_layout() function should exists with the same function as cmake_layout as to set the build_folder directly in the recipe of via a settings set in the conan profile.

### Have you read the CONTRIBUTING guide?

- [ ] I've read the CONTRIBUTING guide


Discussion:
Thanks for the suggestion @hpe-ykoehler 

In order to consider this feature, it would be necessary to have some evidence of autotools projects supporting this flow. Up to my knowledge the vast majority of projects will work building only in-source.
Then, the best way to proceed is to define a very simple example, like using ``conan new autotools_lib``, and first write manually a ``layout()`` method that implements the necessary layout, and then it can be taken from there and abstract that ``layout()`` method into its own helper if necessary.

Could you please provide:
- Some references of existing autotools projects that allow building outside of the source
- A very basic, the most simple autotools based project (ideally starting from ``conan new autotools_lib`` with a manually written ``layout()`` method that would implement the out-of-source build?

Thanks for your feedback.
The out-of-source build feature (also referred to as parallel build trees) of autotools/automake is not new.

You can find many articles about it on Google.  And you can pull recent autotools based package to try it in a shell directly.

As with anything, some package may not use this function and may write build system file that make it incompatible, similar things can also be done in CMake (but it is a little harder to achieve thanks to the higher level language used).   


I have been checking this. 
Autotools helpers already have the ``basic_layout()`` that locates the "build" folder outside of the source folder. This layout will create a ``build-release`` or ``build-debug`` folders for the build by default, and can also be instructed to create a different one with ``--output-folder=myfolder``. You can ``cd`` to that folder and issue the commands for the build.

The ``cmake_layout()`` has a ``build_folder`` argument because its logic is way more complex than the one for ``basic_layout()``. For an autotools project, users can directly do:
```python
def layout(self):
     self.folders.build = "myfolder"
```

Interesting, is there a way to harmonize those two layout so that we can set the build folder to be similar independently of cmake/autotool usage, which is really what I wish here.

I think that the way it should work is that we should set our "desire" build folder value/format, then if the tool can use an out-of-source folder to build, it default to that.

Instead of having one way to set it for cmake, and a different way to set it for autotools... 
Hello @hpe-ykoehler, I have been testing, and it seems that it should work. 

In https://github.com/conan-io/conan/pull/18442, a new parameter is added to the `basic_layout` to define the build folder. The `basic_layout` should be sufficient to handle autotools in this way.



Patch:
diff --git a/conan/tools/layout/__init__.py b/conan/tools/layout/__init__.py
index 33a2cd3fecc..5d5213fdffe 100644
--- a/conan/tools/layout/__init__.py
+++ b/conan/tools/layout/__init__.py
@@ -1,13 +1,16 @@
 import os
 
 
-def basic_layout(conanfile, src_folder="."):
+def basic_layout(conanfile, src_folder=".", build_folder=None):
     subproject = conanfile.folders.subproject
 
     conanfile.folders.source = src_folder if not subproject else os.path.join(subproject, src_folder)
-    conanfile.folders.build = "build" if not subproject else os.path.join(subproject, "build")
-    if conanfile.settings.get_safe("build_type"):
-        conanfile.folders.build += "-{}".format(str(conanfile.settings.build_type).lower())
+    if build_folder:
+        conanfile.folders.build = build_folder if not subproject else os.path.join(subproject, build_folder)
+    else:
+        conanfile.folders.build = "build" if not subproject else os.path.join(subproject, "build")
+        if conanfile.settings.get_safe("build_type"):
+            conanfile.folders.build += "-{}".format(str(conanfile.settings.build_type).lower())
     conanfile.folders.generators = os.path.join(conanfile.folders.build, "conan")
     conanfile.cpp.build.bindirs = ["."]
     conanfile.cpp.build.libdirs = ["."]


Test patch:
diff --git a/test/integration/toolchains/gnu/test_basic_layout.py b/test/integration/toolchains/gnu/test_basic_layout.py
index dad7e73004c..5dc589c9dc9 100644
--- a/test/integration/toolchains/gnu/test_basic_layout.py
+++ b/test/integration/toolchains/gnu/test_basic_layout.py
@@ -1,13 +1,16 @@
 import os
 import platform
 import textwrap
+import pytest
 
 from conan.test.utils.tools import TestClient
 
-
-def test_basic_layout_subproject():
+@pytest.mark.parametrize("basic_layout, expected_path", [
+    ('basic_layout(self)', 'build-release'),
+    ('basic_layout(self, build_folder="custom_build_folder")', 'custom_build_folder')])
+def test_basic_layout_subproject(basic_layout, expected_path):
     c = TestClient()
-    conanfile = textwrap.dedent("""
+    conanfile = textwrap.dedent(f"""
         from conan import ConanFile
         from conan.tools.layout import basic_layout
         class Pkg(ConanFile):
@@ -16,10 +19,10 @@ class Pkg(ConanFile):
             def layout(self):
                 self.folders.root = ".."
                 self.folders.subproject = "pkg"
-                basic_layout(self)
+                {basic_layout}
         """)
     c.save({"pkg/conanfile.py": conanfile})
     c.run("install pkg")
     ext = "sh" if platform.system() != "Windows" else "bat"
-    assert os.path.isfile(os.path.join(c.current_folder, "pkg", "build-release", "conan",
+    assert os.path.isfile(os.path.join(c.current_folder, "pkg", expected_path, "conan",
                                        "conanautotoolstoolchain.{}".format(ext)))