Skip to content

Comments

Add ability to override DFLAGS env variable in test suite#7845

Merged
wilzbach merged 1 commit intodlang:masterfrom
JinShil:dflags
Feb 12, 2018
Merged

Add ability to override DFLAGS env variable in test suite#7845
wilzbach merged 1 commit intodlang:masterfrom
JinShil:dflags

Conversation

@JinShil
Copy link
Contributor

@JinShil JinShil commented Feb 6, 2018

The test suite makefile adds the import directories for druntime and phobos to the DFLAGS environment variable:

dmd/test/Makefile

Lines 173 to 177 in c55c9be

DRUNTIME_PATH=../../druntime
PHOBOS_PATH=../../phobos
# link against shared libraries (defaults to true on supported platforms, can be overridden w/ make SHARED=0)
SHARED=$(if $(findstring $(OS),linux freebsd),1,)
DFLAGS=-I$(DRUNTIME_PATH)/import -I$(PHOBOS_PATH) -L-L$(PHOBOS_PATH)/generated/$(OS)/$(BUILD)/$(MODEL)

This makes it impossible to write tests for no- or minimal-runtime programming, due to the implicit import of object.d. See #7825 for evidence.

This PR adds a DFLAGS: test variable that clears the DFLAGS environment variable enabling us to write no- or minimal-runtime tests among other potential possibilities.

@dlang-bot
Copy link
Contributor

Thanks for your pull request, @JinShil!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

@wilzbach
Copy link
Contributor

wilzbach commented Feb 6, 2018

The CI failures are correct but unrelated to this PR - see #7838 (comment)

@wilzbach
Copy link
Contributor

wilzbach commented Feb 6, 2018

DFLAGS=-I$(DRUNTIME_PATH)/import -I$(PHOBOS_PATH) -L-L$(PHOBOS_PATH)/generated/$(OS)/$(BUILD)/$(MODEL)

Interesting. Shouldn't it overwrite the default dmd.conf with -conf= too? I guess it didn't make a difference to far because the auto-generated one is more or less identical to this command.
(edit: I submitted #7846 - let's see what breaks)

I fear a bit that exposing DFLAGS could be abused or confused with REQUIRED_ARGS or PERMUTE_ARGS. How about a NO_DFLAGS setting that - if set - would set the DFLAGS to -conf=? Then REQUIRED_ARGS / PERMUTE_ARGS / ARG_SETS could be used as usual.

@JinShil
Copy link
Contributor Author

JinShil commented Feb 6, 2018

How about a NO_DFLAGS setting that - if set - would set the DFLAGS to -conf=?

-conf= is already being set:

string command = format("%s -conf= -m%s -I%s %s %s -od%s -c %s %s", envData.dmd, envData.model, input_dir,

A NO_DFLAGS: test variable that simply wipes out the DFLAGS environment variable would also work for my specific needs, but I thought the DFLAGS: test variable might open up few more possibilities. I'm impartial; either way will work for me.

@wilzbach
Copy link
Contributor

wilzbach commented Feb 6, 2018

I'm impartial; either way will work for me.

Same here. It was just an idea. Has someone a (strong) opinion about this?

@JinShil
Copy link
Contributor Author

JinShil commented Feb 8, 2018

After giving this some thought, I think the NO_DFLAGS: test variable would probably be the better solution to, as was alluded to, ensure we have consistent and predictable usage of our test variables. NO_DFLAGS: has been implemented.

test/d_do_test.d Outdated

// Clear the DFLAGS environment variable if it was specified in the test file
if (testArgs.noDflags)
environment.remove("DFLAGS");
Copy link
Contributor

@wilzbach wilzbach Feb 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


edit: ah I see `-conf=` is already set at other parts here.

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable to me.

@wilzbach wilzbach added the Merge:72h no objection -> merge The PR will be merged if there are no objections raised. label Feb 8, 2018
@WalterBright
Copy link
Member

Shouldn't

DFLAGS=

do the trick of setting it to nothing?

@JinShil
Copy link
Contributor Author

JinShil commented Feb 8, 2018

Shouldn't DFLAGS= do the trick of setting it to nothing?

Where? In Makefile? If you set DFLAGS to nothing in Makefile then it applies to all tests. The goal with this PR is to set it to nothing for only specific tests. To do that it must be done in the testxxx.d file, and in there DFLAGS= syntax is not supported.

Originally, I created a DFLAGS: test variable that would override the DFLAGS environment variable, but then that leaves us with too many different ways to set compiler flags: DFLAGS, REQUIRED_ARGS, PERMUTE_ARGS, and ARGS_SETS. That will only lead to inconsistency and unpredictability in how the compiler flags are set for the test suite. The NO_DFLAGS test argument allows us to clear the DFLAGS environment variable individually for each test, without opening the flood gates to all the different creative ways one might choose to set compiler flags.

It could be argued that we could simplify the test suite by removing all the other test variables and only allowing DFLAGS to be overridden or appended, but that would require changing every test file in the repository, and you already scolded me twice for pulling PRs that touch too many files.

@WalterBright
Copy link
Member

The goal with this PR is to set it to nothing for only specific tests. To do that it must be done in the testxxx.d file, and in there DFLAGS= syntax is not supported.

Sorry, the DFLAGS: syntax. Since these are specific to each test file, there is no earthly reason to have:

DFLAGS:

in there unless one wants to clear DFLAGS.

The NO_DFLAGS test argument allows us to clear the DFLAGS environment variable individually for each test, without opening the flood gates to all the different creative ways one might choose to set compiler flags.

Good point. Just don't allow anything for DFLAGS: but a blank line.

I.e. just rename NO_DFLAGS to DFLAGS. (You already must have dealt with the issue of what to do with: NO_DFLAGS: foo).

@WalterBright
Copy link
Member

It could be argued that we could simplify the test suite by removing all the other test variables and only allowing DFLAGS to be overridden or appended

Not by me.

@wilzbach
Copy link
Contributor

wilzbach commented Feb 9, 2018

Good point. Just don't allow anything for DFLAGS: but a blank line.

I bet this will confuse people and they will waste time wondering why DFLAGS doesn't take effect or even assume that something is checked which isn't.
Please let's use NO_DFLAGS - it's absolutely clear what's going on and can't be accidentally misused.

@JinShil
Copy link
Contributor Author

JinShil commented Feb 9, 2018

I bet this will confuse people and they will waste time wondering why DFLAGS doesn't take effect or even assume that something is checked which isn't.
Please let's use NO_DFLAGS - it's absolutely clear what's going on and can't be accidentally misused.

I agree. @WalterBright, can we convince you to keep this PR as is and support NO_DFLAGS for the reason given above?

test/d_do_test.d Outdated
{
string file = cast(string)std.file.read(input_file);

string ignore;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put ignore in it's own scope

{
    string ignore;
    testArgs.noDflags = findTestParameter(envData, file, "NO_DFLAGS", ignore);
}

@marler8997
Copy link
Contributor

marler8997 commented Feb 9, 2018

I wonder how many tests don't need druntime/phobos? Probably the majority correct? Maybe the better solution is to have DFLAGS be "opt-in" instead of "opt-out"?

Would also make it a bit clearer that using druntime/phobos should be the "atypical" case.

@JinShil
Copy link
Contributor Author

JinShil commented Feb 9, 2018

I wonder how many tests don't need druntime/phobos?

I bet most, if not all, don't need Phobos, but I'd be willing to bet 99.9% need druntime simply because of object.d. Afterall that's where fundamentals of the language like Object, string, and size_t are declared and defined.

@WalterBright
Copy link
Member

I bet this will confuse people

How? I set/reset env variables all the time, and setting them to nothing is VAR=. There's nothing confusing about it.

and they will waste time wondering why DFLAGS doesn't take effect or even assume that something is checked which isn't.

If they set DFLAGS=something then they should get an error message. I don't see how that is confusing.

@marler8997
Copy link
Contributor

I bet most, if not all, don't need Phobos, but I'd be willing to bet 99.9% need druntime simply because of object.d.

Ah ok, nevermind then :)

@WalterBright
Copy link
Member

@wilzbach Keep in mind that you have another PR with Use -conf= to overwrite the default dmd config, not -no_conf :-)

@marler8997
Copy link
Contributor

DFLAGS= works in .sh files, but doesn't work in .d files does it?

@JinShil
Copy link
Contributor Author

JinShil commented Feb 9, 2018

Yes, I believe we'll have to use DFLAGS= in .sh files and DFLAGS: in .d files if we go with @WalterBright's preference.

@marler8997
Copy link
Contributor

DFLAGS: for .d files and DFLAGS= for .sh files seems more consistent. But NO_DFLAGS: seems more intuitive than DFLAGS:...sounds like a wash to me

@wilzbach wilzbach removed the Merge:72h no objection -> merge The PR will be merged if there are no objections raised. label Feb 9, 2018
@wilzbach
Copy link
Contributor

wilzbach commented Feb 9, 2018

How? I set/reset env variables all the time, and setting them to nothing is VAR=. There's nothing confusing about it.
...

I was talking about things like:

// DFLAGS: -version=Foo

version(Foo) {
 ... // this is never executed, but assumed by contributor and reviewers to be executed & tested
}

But NO_DFLAGS: seems more intuitive than DFLAGS:...sounds like a wash to me

Maybe it should have been named NO_CONF
Well, there are already these accepted in-test boolean variables:

  • COMPILE_SEPARATELY (set to enable)
  • LINK (set to enable)

If they set DFLAGS=something then they should get an error message. I don't see how that is confusing.

Ok. We should do this no matter how the variable is named.

`@wilzbach Keep in mind that you have another PR with Use -conf= to overwrite the default dmd config, not -no_conf

That would imply we should use CONF:, no?
Not a bad idea!

CC @CyberShadow who has always shown a lot of wisdom in such CLI usability questions.

@JinShil
Copy link
Contributor Author

JinShil commented Feb 9, 2018

OK, I've implemented DFLAGS:. d_do_test.d will throw an error if it is not empty.

I still need to figure out why this isn't working for Windows though.

test/d_do_test.d Outdated
if (testArgs.dflags != "")
throw new Exception("The DFLAGS test argument must be empty");

environment["DFLAGS"] = testArgs.dflags;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe "" for clarity?

@JinShil
Copy link
Contributor Author

JinShil commented Feb 10, 2018

Interesting:
Win32: import object (..\..\druntime\import\object.d) --> WRONG!
Win32_64: import path[0] = fail_compilation --> Correct!

@braddr and @rainers, Do you have any ideas why Win32 is still importing object.d in this case (See AutoTester results)

@rainers
Copy link
Member

rainers commented Feb 10, 2018

Clearing the environment variable with environment["DFLAGS"] = "" doesn't work. Using putenv helps, but the actual issue is probably in std.process.

@JinShil
Copy link
Contributor Author

JinShil commented Feb 10, 2018

I tried calling Win32 API function SetEnvironmentVariable, but that didn't work either. @braddr, is the DFLAGS variable set in the "System" environment variables on the Win32 machine?

@wilzbach
Copy link
Contributor

@marler8997
Copy link
Contributor

It looks like d_do_test is using the system function to invoke the compiler. I believe that function will just inherit its environment variables from the parent process, however, I don't think setting environment["DFLAGS"] = "" will actually change the process's environment variables. Did you try putenv? If that doesn't work, we could probably use a different function to invoke the compiler (other than system) that could accept environment variables to pass to the child process.

@JinShil
Copy link
Contributor Author

JinShil commented Feb 10, 2018

It looks like d_do_test is using the system function to invoke the compiler. I believe that function will just inherit its environment variables from the parent process

Isn't the process executing d_do_test the parent process? If so, the environment variables are cleared there before the call to system, so it should work, at least as I understand it.

Did you try putenv?

putenv is a POSIX function, isn't it? The only platform that doesn't work is Win32. Even Win32_64 works. There's something odd about Win32.

@marler8997
Copy link
Contributor

marler8997 commented Feb 11, 2018

Ah, it looks like std.process actually does call SetEnvironmentVariable when you set environment["DFLAGS"] = "". Maybe win32 isn't trying to import object.d. Maybe try adding something into the test file that explicitly depends on it?

// string is defined in object.d, this should guarantee that object.d is getting loaded
static assert(string.sizeof > 0);

@@ -0,0 +1,15 @@
/*
DFLAGS:
REQUIRED_ARGS:
Copy link
Contributor

@wilzbach wilzbach Feb 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try -v here to debug win32

(edit: I just tried this for you)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did. See the result here: https://auto-tester.puremagic.com/show-run.ghtml?projectid=1&runid=3027610&isPull=true

import object (....\druntime\import\object.d)

I don't know where that's coming from.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(edit: I just tried this for you)

You'll probably want to disable other platforms or the auto-tester will fail and will never get around to running the test in question.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry. Feel free to drop my commit.
We should really print D_FLAGS with -v too ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really print D_FLAGS with -v too ...

#7865 - this might help you.

@rainers
Copy link
Member

rainers commented Feb 11, 2018

putenv is a POSIX function, isn't it?

The OMF library snn.lib has putenv, too, it just isn't declared in core.stdc.stdlib. Using putenv("DFLAGS="); with an appropriate declaration worked for me for yesterday.

@JinShil
Copy link
Contributor Author

JinShil commented Feb 11, 2018

Thanks @rainers. Using putenv from snn.lib seems to have worked. I'll do some more testing on std.process.environment and either submit a PR to phobos, or file a bug. For now, I've implemented a workaround just for Win32.

This should now be ready to go.

@marler8997
Copy link
Contributor

Should a bug be filed for std.process?

@JinShil
Copy link
Contributor Author

JinShil commented Feb 11, 2018

Should a bug be filed for std.process?

Yes. If I can create an isolated test case, I'll file a bug.

@JinShil
Copy link
Contributor Author

JinShil commented Feb 12, 2018

Phew! What a chore that turned out to be. I had to make a couple of changes (it worked once and then started failing again... weird). This should be ready to go now.

I'll file a bug for std.process after I get in front of a Windows machine, and assuming I can reproduce the problem in an isolated test.

@JinShil JinShil removed the Review:WIP Work In Progress - not ready for review or pulling label Feb 12, 2018
@marler8997
Copy link
Contributor

I've created an issue so we don't forget to address this: https://issues.dlang.org/show_bug.cgi?id=18425

test/d_do_test.d Outdated
version(Win32)
{
char[] varExpression = cast(char[])"DFLAGS=\0";
putenv(varExpression.ptr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declaring extern(C) int putenv(const char *); globally and calling putenv("DFLAGS="); worked for me. The literal already has the trailing zero and converts implicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@rainers
Copy link
Member

rainers commented Feb 12, 2018

I suspect the issue is that SetEnvironmentVariable is called with an empty string, while removal should be done with a null argument. Not sure why this works for Win64, though.

@marler8997
Copy link
Contributor

Hmmm, but deleting DFLAGS or setting it to an empty string should still produce the same result...

@JinShil
Copy link
Contributor Author

JinShil commented Feb 12, 2018

I suspect the issue is that SetEnvironmentVariable is called with an empty string, while removal should be done with a null argument

I tried calling SetEnvironmentVariable directly with both null and empty strings, and neither worked.

@marler8997
Copy link
Contributor

Might have something to do with mixing native windows functions with posix. The system posix function may not pick up environment variables from SetEnvironmentVariable

@rainers
Copy link
Member

rainers commented Feb 12, 2018

Hmmm, but deleting DFLAGS or setting it to an empty string should still produce the same result...

Maybe the empty string is silently ignored. Both snn.lib and libcmt.lib implement putenv via SetEnvironmentVariable and convert it to the null parameter for removal.

@wilzbach
Copy link
Contributor

Thanks a lot @JinShil @rainers @marler8997 for this diligent debugging work. We should really look into fixing std.process :O

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants