Repository: conan-io/conan

Issue:
CMake generator is not optional on Windows
Create a CMake object in the conanfile.py  with the following settings:
- os_build = Windows
- compiler = a custom compiler
- compiler_version = some version
- arch = None

will always raise the following error:

    cmake = CMake(self)
    TypeError: argument of type 'NoneType' is not iterable

Looks like `get_generator` in cmake_flags.py returns None because of the missing `arch`. The same would happen without a compiler or compiler_version. Later the empty generator is passed to `is_multi_configuration` where the error is raised.
I would expect `get_generator` to return the default `MinGW Makefiles` in this case. Or maybe just print a more helpful error message about the missing arch or generator.

Conan version 1.11.2

- [ x] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
- [x ] I've specified the Conan version, operating system version and any tool that can be relevant.
- [x ] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.




Discussion:
Hi @ChristophStrehle 

If one generator can't be deduced with some good confidence from the settings, then it is expected that it will fail (a different thing is that the error message needs to be improved).

You have a ``generator=None`` argument in the constructor, so you can easily do it yourself:

```python
cmake = CMake(self, generator="MinGW Makefiles")
```

Returning "MinGW Makefiles" generator by default doesn't seem robust enough, it is better to fail and let the user specify the generator themselves.

So agree on the more helpful message, lets fix it. Thanks for reporting!
Hi @memsharded 

thank you for your fast replay. I agree, if you can't deduce the generator you should fail.

We actually build this conanfile on a Linux and on a Windows machine. So I would need to set the generator depending on the current os. The Windows machine is my local machine, so I'm using the CONAN_CMAKE_GENERATOR variable for now. It just took me a while to figure out what is gonging on.

I'm just wondering why is it a valid option to return MinGW Makefiles if I specify the `arch` and a compiler different to Visual Studio?

Having a second look at the code, I agree, you could be right. 

That is the only case that it is returning ``None``, and then, returning by default ``MinGW Makefiles`` in Windows, won't break anyone. 

Lets try to change it then.

Resolving patch:
diff --git a/conans/client/build/cmake_flags.py b/conans/client/build/cmake_flags.py
--- a/conans/client/build/cmake_flags.py
+++ b/conans/client/build/cmake_flags.py
@@ -36,8 +36,7 @@ def get_generator(settings):
 
     if not compiler or not compiler_version or not arch:
         if os_build == "Windows":
-            # Not enough settings to set a generator in Windows
-            return None
+            return "MinGW Makefiles"
         return "Unix Makefiles"
 
     if compiler == "Visual Studio":


Test patch:
diff --git a/conans/test/functional/generators/cmake_generator_test.py b/conans/test/functional/generators/cmake_generator_test.py
new file mode 100644
--- /dev/null
+++ b/conans/test/functional/generators/cmake_generator_test.py
@@ -0,0 +1,64 @@
+import unittest
+
+from nose.plugins.attrib import attr
+
+from conans import tools
+from conans.test.utils.tools import TestClient
+
+
+CONAN_RECIPE = """
+from conans import ConanFile, CMake
+
+class FooConan(ConanFile):
+    name = "foo"
+    version = "0.1"
+    settings = "os_build", "compiler", "build_type"
+    generators = "cmake"
+    exports = '*'
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+"""
+
+
+CPP_CONTENT = """
+int main() {}
+"""
+
+CMAKE_RECIPE = """
+cmake_minimum_required(VERSION 2.8.12)
+project(dummy CXX)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup()
+
+add_executable(dummy dummy.cpp)
+"""
+
+
+@attr("slow")
+class CMakeGeneratorTest(unittest.TestCase):
+
+    def _generator_test_helper(self, os_build, makefile):
+        try:
+            client = TestClient()
+            client.save({"conanfile.py": CONAN_RECIPE,
+                        "CMakeLists.txt": CMAKE_RECIPE,
+                        "dummy.cpp": CPP_CONTENT})
+            client.run("create . lasote/testing -s os_build={}".format(os_build))
+        finally:
+            self.assertNotIn("TypeError: argument of type 'NoneType' is not iterable", client.user_io.out)
+            self.assertNotIn("ERROR:", client.user_io.out)
+            self.assertIn("Check for working CXX compiler", client.user_io.out)
+            self.assertIn('cmake -G "{}"'.format(makefile), client.user_io.out)
+
+    def test_cmake_default_generator_linux(self):
+        self._generator_test_helper("Linux", "Unix Makefiles")
+
+    @unittest.skipUnless(tools.os_info.is_windows, "MinGW is only supported on Windows")
+    def test_cmake_default_generator_windows(self):
+        self._generator_test_helper("Windows", "MinGW Makefiles")
+
+    def test_cmake_default_generator_osx(self):
+        self._generator_test_helper("Macos", "Unix Makefiles")
diff --git a/conans/test/unittests/client/build/cmake_test.py b/conans/test/unittests/client/build/cmake_test.py
--- a/conans/test/unittests/client/build/cmake_test.py
+++ b/conans/test/unittests/client/build/cmake_test.py
@@ -1037,7 +1037,7 @@ def instance_with_os_build(os_build):
         self.assertEquals(cmake.generator, "Unix Makefiles")
 
         cmake = instance_with_os_build("Windows")
-        self.assertEquals(cmake.generator, None)
+        self.assertEquals(cmake.generator, "MinGW Makefiles")
 
         with tools.environment_append({"CONAN_CMAKE_GENERATOR": "MyCoolGenerator"}):
             cmake = instance_with_os_build("Windows")