-
Notifications
You must be signed in to change notification settings - Fork 984
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
[NMakeToolchain] Refactoring to expose similar interface than other toolchains & honor build config #12665
[NMakeToolchain] Refactoring to expose similar interface than other toolchains & honor build config #12665
Conversation
baf21f1
to
b8af0a4
Compare
b8af0a4
to
52e2110
Compare
[conf]
[conf]
[conf]
conf_compilers = self._conanfile.conf.get("tools.build:compiler_executables", default={}, check_type=dict) | ||
if conf_compilers: | ||
compilers_mapping = { | ||
"AS": "asm", | ||
"CC": "c", | ||
"CPP": "cpp", | ||
"CXX": "cpp", | ||
"RC": "rc", | ||
} | ||
for env_var, comp in compilers_mapping.items(): | ||
if comp in conf_compilers: | ||
env.define(env_var, conf_compilers[comp]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of scope of this PR, but I believe this toolchain should set all these env vars by default for clang-cl if their corresponding tools.build:compiler_executables key is not set.
It would be nice in order to avoid this kind of fragile logic (and broken for clang mingw):
https://github.com/conan-io/conan-center-index/blob/2ecc63a88002b1294f0ea0650f27c6012933aafa/recipes/libjpeg/all/conanfile.py#L33-L35
https://github.com/conan-io/conan-center-index/blob/2ecc63a88002b1294f0ea0650f27c6012933aafa/recipes/libjpeg/all/conanfile.py#L106-L114
@memsharded could you review this PR please? It would be nice to guarantee that we can use NMakeToolchain in conan-center and hope honoring all conf from profile to avoid discrepancies in recipes behavior. |
env.append("CFLAGS", self._cflags) | ||
env.append("CPPFLAGS", self._cxxflags) | ||
env.append("CXXFLAGS", self._cxxflags) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why defining these variables? If they are used, it will be a duplication of flags (they are already defined in CL
). If they are not used, why defining them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess they can be removed yes, as you wish. They are official documented macro of NMake: https://learn.microsoft.com/en-us/cpp/build/reference/special-nmake-macros?view=msvc-170
But defining them may improve robustness, I'm not sure. I'm pretty sure it doesn't hurt at least. It deserves extra experimentations since microsoft documentation is poor. Maybe remove them and left a comment?
By the way, from what I understand from microsoft documentation, CL and LINK are not specific to NMake but to cl & link.
# Rearrange defines to macro / value dict | ||
conf_preprocessors = {} | ||
for define in defines: | ||
if "=" in define: | ||
key, value = define.split("=", 1) | ||
if not value: | ||
conf_preprocessors[key] = "1" | ||
else: | ||
conf_preprocessors[key] = value | ||
else: | ||
conf_preprocessors[define] = "1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of re-arranging, provide the defines already in a dict, and compose it into list when necessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pytest.mark.parametrize
cannot take dict values AFAIK. Do you have an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[{"TEST_DEFINITION1": None}, {"TEST_DEFINITION2": "0"}, .........],
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I've tried and it didn't work. I can try again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually a change like this wouldn't be robust enough.
If I try to inject /DTEST_DEFINITION1
for {"TEST_DEFINITION1": None}
as an input, it won't be understood like this by check_exe_run()
which would expect {"TEST_DEFINITION1": "1"}
. /DTEST_DEFINITION1
is equivalent to /DTEST_DEFINITION1=1
, but I also want to test that /DTEST_DEFINITION1
AND /DTEST_DEFINITION1=1
work in NMakeToolchain
. I even want to test that /DTEST_DEFINITION1=
works. How to disambiguate when I serialize this dictionary for tools.build:defines
, and even after when I pass this dictionary to check_exe_run
?
Moreover source code generated by gen_function_cpp()
is not robust to a true empty definition like /DTEST_DEFINITION1=
.
compilers_mapping = { | ||
"AS": "asm", | ||
"CC": "c", | ||
"CPP": "cpp", | ||
"CXX": "cpp", | ||
"RC": "rc", | ||
} | ||
for env_var, comp in compilers_mapping.items(): | ||
if comp in conf_compilers: | ||
env.define(env_var, conf_compilers[comp]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NMake not listening to these CC/CXX, etc env-vars, only to CL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not what microsoft documentation says: https://learn.microsoft.com/en-us/cpp/build/reference/special-nmake-macros
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to make it work while developing the NMakeToolchain and for some reason it didn't work. If it is expected to work then the way to move this forward is:
- remove the injection of flags into
CL
and use the other options flags as their own env-vars, - modify
NMakeDeps
to be consistent with this - check that tests correctly work, this test is not validating anywhere that flags
["/GL"], ["/GL"], ["/LTCG"], ["/LTCG"]
are actually being honored
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed CFLAGS, CXXFLAGS and CPPFLAGS, they have no effect by default indeed. I've kept CC & CXX & CPP, I'm pretty sure these ones are listened. By default CPP is cl
and if compiler is clang-cl, CPP must be changed.
if cppstd: | ||
cppflags.append(cppstd) | ||
from conan.tools.microsoft import msvc_runtime_flag | ||
def _get_msvc_runtime_flag(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unnecessary, the formatting of flag is doing nothing, the msvc_runtime_flag()
can be used directly instead of this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does something, it prepends /
. It's just a copy paste of an autotoolstoolchain private method.
# Rearrange defines to macro / value dict | ||
conf_preprocessors = {} | ||
for define in defines: | ||
if "=" in define: | ||
key, value = define.split("=", 1) | ||
if not value: | ||
conf_preprocessors[key] = "1" | ||
else: | ||
conf_preprocessors[key] = value | ||
else: | ||
conf_preprocessors[define] = "1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[{"TEST_DEFINITION1": None}, {"TEST_DEFINITION2": "0"}, .........],
("msvc", "190", "dynamic", "14", "Release", [], [], [], [], []), | ||
("msvc", "190", "dynamic", "14", "Release", | ||
["TEST_DEFINITION1", "TEST_DEFINITION2=0", "TEST_DEFINITION3=", "TEST_DEFINITION4=TestPpdValue4"], | ||
["/GL"], ["/GL"], ["/LTCG"], ["/LTCG"]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Who checks and validates that these ["/GL"], ["/GL"], ["/LTCG"], ["/LTCG"] flags are being honored?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how to test that in produced binaries. I'm not sure that it's really tested in any other functional test of conan client actually. The best I could do is a unittest to check whether these flags are passed to CL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is true, it is difficult. I have checked other tests for other build systems, and they do check just reading the generated files or the command line. Still worth it, at least guarantee they are there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll see what I can do
|
Changelog: Fix: Refactoring of
NMakeToolchain
to expose similar attributes than other toolchains, and honor build config like cflags, cxxflags, sharedlinkflags, exelinkflags, defines & compiler_executables.Docs: conan-io/docs#2848
develop
branch, documenting this one.Note: By default this PR will skip the slower tests and will use a limited set of python versions. Check here how to increase the testing level by writing some tags in the current PR body text.