Conversation
| it('should preserve quotes', () => { | ||
| assert.deepEqual( | ||
| win.adjustLibraries([ '"some path/lib1"', '-l"lib2"', | ||
| win.adjustLibraries([ '"some path/lib1"', '-l"lib2"', |
There was a problem hiding this comment.
My IDE keeps eating this trailing white space...
Let it DIE ;)
|
indutny
left a comment
There was a problem hiding this comment.
Thank you for submitting this! There are some nits that need to be fixed before landing it. Let me know if you have any questions!
Should other PRs be closed, considering that this one includes commits from the others?
| } else if (process.platform === 'win32') { | ||
| ar = 'lib.exe'; | ||
| ld = 'link.exe'; | ||
| ar = gyp.bindings.which('lib.exe'); |
There was a problem hiding this comment.
This should be supplied by setting PATH in environment file, not by using which... Why is it necessary?
There was a problem hiding this comment.
🤔😕
Conceptually you should right, but it failed for me (I have multiple link.exe in my path, and ninja used the wrong one), even though environment.x64 was generated correctly.
If I fix this somehow else, a bunch of stuff can be skipped.
There was a problem hiding this comment.
That's the point of environment files. If it doesn't work - would you mind posting results of which link.exe and the environment file itself?
| main.declare('ld_host', ld); | ||
| main.declare('ldxx_host', ldxx); | ||
| main.declare('ar_host', ar); | ||
|
|
| p = p.replace(/\$!INTERMEDIATE_DIR/g, intDir); | ||
| } | ||
|
|
||
| p = p.replace(/(\.\.[\\\/])\$\|CONFIGURATION_NAME/g, `$1${this.configDir}`); |
There was a problem hiding this comment.
What exactly gets there in p and how? Why does it have ../ in it?
There was a problem hiding this comment.
The (faulty) use case in icu-generic.gyp assumes it knows where the output is base on configuration and calles for
'-P', '../../<(CONFIGURATION_NAME)'
My line assumes that path manipulation (../) with CONFIGURATION_NAME actually want the configuration dir, not just name.
So we get ../../out/Release and not just ../../Release.
There was a problem hiding this comment.
How does it work with regular GYP?
There was a problem hiding this comment.
Voodoo
MSVS at least, resolves paths for actions from the dir of the project file.
I think in our case path resolution for actions start at base of build.
There was a problem hiding this comment.
Ohh, just managed to run gyp -fninja for msvs. Same place is broken.
There was a problem hiding this comment.
| const actionRule = action.action_name + '_' + this.index; | ||
| const safeActionName = action.action_name.replace(/\s/g, '_'); | ||
| global.action_names = (global.action_names || {}); | ||
| const nameAtConfig = global.action_names[this.config] || (global.action_names[this.config] = {}); |
There was a problem hiding this comment.
80 column limit? Does it pass make lint?
There was a problem hiding this comment.
You may also just use make format to fix it.
| list.forEach((action) => { | ||
| const actionRule = action.action_name + '_' + this.index; | ||
| const safeActionName = action.action_name.replace(/\s/g, '_'); | ||
| global.action_names = (global.action_names || {}); |
There was a problem hiding this comment.
It should store action_names in some JS instance, perhaps NinjaMain. Using global is a no-go here. Sorry!
There was a problem hiding this comment.
NP (although gyp.js is a command line tool, not a service ;) ).
There was a problem hiding this comment.
It is an npm module first of all! :)
| let stack_commit_size = linker.StackCommitSize || ''; | ||
| if (stack_commit_size) stack_commit_size = ',' + stack_commit_size; | ||
| ldflags.push('/STACK' + stack_reserve_size + stack_commit_size); | ||
| ldflags.push('/STACK:' + stack_reserve_size + stack_commit_size); |
There was a problem hiding this comment.
Not me, the linker wan't happy.
| process.stderr.write(message + '\n'); | ||
| }; | ||
|
|
||
| exports.which = (cmd, opt) => `"${which(cmd, opt)}"`; |
| if (version === 'auto' && env['VS100COMNTOOLS'] || version === '2010') { | ||
| version = '2010'; | ||
| tools = path.join(env.VS120COMNTOOLS, '..', '..'); | ||
| function tryVS7() { |
There was a problem hiding this comment.
Could these functions be hoisted out of resolveDevEnvironment?
| win.setEnvironment = function setEnvironment(target_arch) { | ||
| const lines = win.resolveDevEnvironment(target_arch); | ||
| lines.forEach(l => { | ||
| const kv = l.split('='); |
There was a problem hiding this comment.
Could any of env vars have several =?
| const lines = win.resolveDevEnvironment(target_arch); | ||
| lines.forEach(l => { | ||
| const kv = l.split('='); | ||
| process.env[kv[0]] = kv[1]; |
There was a problem hiding this comment.
Let's return object instead of modifying global state.
There was a problem hiding this comment.
I wanted this for the which later.... So pending that.
|
Found a way to get rid of all the |
|
Got rid of the whole |
| // TODO(indutny): escape quotes in res | ||
| return `cmd.exe /s /c "${res}"`; | ||
| const wrap = gyp.platform.win.ninjaWrap; | ||
| return `${wrap} powershell -Command ${res.replace(/ & /g, ' ; ')}`; |
There was a problem hiding this comment.
powershell is way more consistent with compound commands (e.g. {cd; xx.exe; copy xx})
| win.genEnvironment = function genEnvironment(outDir, target_arch) { | ||
| const env = win.resolveDevEnvironment(target_arch); | ||
| const envBlock = Object.keys(env) | ||
| // .filter(key => key.match(IMPORTANT_VARS)) |
There was a problem hiding this comment.
Taking all, less complex, maybe even works better...
There was a problem hiding this comment.
Keep the filter out, yes?
Just look at what vcvarscmd.bat adds
I don't know what's up with that 3 extra fails, but still... |
indutny
left a comment
There was a problem hiding this comment.
Left few more comments. Moving in the right direction! Thank you
| const path = gyp.bindings.path; | ||
| const process = gyp.bindings.process; | ||
|
|
||
| const actionNames = {}; |
There was a problem hiding this comment.
Still it is global here 😉 It should live in NinjaMain or whatever.
There was a problem hiding this comment.
That's module scope, I thought it would be even cleaner, but sure.
There was a problem hiding this comment.
Well, it should be per-instance not per-application. That's my point.
| const ninjaWrap = `ninja -t msvc ${envFile}--`; | ||
| win.setupNinjaWrapper = function (target_arch) { | ||
| const envFile = win.getEnvFileName(target_arch); | ||
| this.ninjaWrap = `ninja -t msvc -e ${envFile} --`; |
| win.genEnvironment = function genEnvironment(outDir, target_arch) { | ||
| const env = win.resolveDevEnvironment(target_arch); | ||
| const envBlock = Object.keys(env) | ||
| // .filter(key => key.match(IMPORTANT_VARS)) |
| targetDict, | ||
| ninjas, | ||
| config: this.config, | ||
| actionNames, |
There was a problem hiding this comment.
Trickling these two into every Ninja
There was a problem hiding this comment.
Heh, true. Could we use actionNames: actionNames here?
There was a problem hiding this comment.
Don't you like "Object literals Shorthand property names" that's even ES2015
|
I added another commit with some more windows black magic for finding vs2017 in restricted environments. |
e2e0ace to
e267594
Compare
|
Would you consider adding this as a dep? |
|
That sounds good to me! |
| npm-debug.log | ||
| out/ | ||
| coverage/ | ||
| tools/*.exe |
There was a problem hiding this comment.
This is no longer needed, right?
| } | ||
|
|
||
| // First one is in order to outsmart silly GYP file writers | ||
| p = p.replace(/(\.\.[\\\/])+\$\|CONFIGURATION_NAME/g, productDir); |
There was a problem hiding this comment.
I'm really afraid of doing this. Could we have a test case for this?
There was a problem hiding this comment.
I wrote one, but it really concocted...
There was a problem hiding this comment.
Alright, so what was the exact problem? Which path did it get here, and what was the right path to expect?
There was a problem hiding this comment.
So the GYP is:
{
# build final .dat -> .obj
'action_name': 'genccode',
'inputs': [ '<(SHARED_INTERMEDIATE_DIR)/icutmp/icudt<(icu_ver_major)<(icu_endianness).dat' ],
'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/icudt<(icu_ver_major)<(icu_endianness)_dat.obj' ],
'action': [ '../../<(CONFIGURATION_NAME)/genccode',
'-o',
'-d', '<(SHARED_INTERMEDIATE_DIR)/',
'-n', 'icudata',
'-e', 'icusmdt<(icu_ver_major)',
'<@(_inputs)' ],
}
The result (pre patch) is:
rule genccode
command = cmd.exe$ /s$ /c$ "cd$ ..\..\tools\icu$ &$ ..\..\Release\genccode$ $
-o$ -d$ ..\..\out\Release\gen\$ -n$ icudata$ -e$ icusmdt58$ $
..\..\out\Release\gen\icutmp\icudt58l.dat"
They are trying to reach the output dir, but the path voodoo fails, ..\..\Release\genccode is not there, it's at ..\..\out\Release\genccode
so after patch:
rule genccode
command = cmd.exe$ /s$ /c$ "cd$ ..\..\tools\icu$ &$ $
..\..\out\Release\genccode$ -o$ -d$ ..\..\out\Release\gen\$ -n$ icudata$ $
-e$ icusmdt58$ ..\..\out\Release\gen\icutmp\icudt58l.dat"
I made a PR to fix the root nodejs/node#11217
There was a problem hiding this comment.
So this should not work on Unixes either as it is right now, right?
There was a problem hiding this comment.
Because other than ninja the other generated output goes in the root dir, and artifacts go in .../node/Release/... or ..../node/Debug/... and so ../../ in the path voodoo is base of root source (.../node/)
| let targetDict = this.targetDicts[target].configurations[this.config]; | ||
| const ninja = new Ninja({ | ||
| index: index, | ||
| index, |
| targetDict, | ||
| ninjas, | ||
| config: this.config, | ||
| actionNames, |
There was a problem hiding this comment.
Heh, true. Could we use actionNames: actionNames here?
| return ret.find(v => v[0] === maxVer)[1]; | ||
| } | ||
|
|
||
| win._forTesting = {tryVS7_powershell, tryVS7_CSC, tryVS7_registry}; |
There was a problem hiding this comment.
I guess they can be just put in exports.
| } | ||
| const env = lines.reduce((s, l) => { | ||
| const kv = l.split('='); | ||
| s[kv[0]] = kv[1]; |
There was a problem hiding this comment.
Why not keep only important lines?
There was a problem hiding this comment.
Who are we to judge, newer version of VS might add more variables (actually I think they did in 2017), the VsDevCmd.bat runs for almost 20 seconds to setup the ENV, it probably knows what it's doing... and anyway ninja does some more environment voodoo with the -t msvs -e xxx wrapper
There was a problem hiding this comment.
I just don't want to get any unwanted extras from default global env variables.
There was a problem hiding this comment.
We could do a post - pre delta calculation. I use some of these delta file my day2day dev environment.
| }; | ||
|
|
||
| win.genEnvironment = function genEnvironment(outDir, version, arch) { | ||
| function tryVS7_powershell() { |
There was a problem hiding this comment.
Camel case? Considering that all of these functions are prefixed with tryVS7, should we put them in win/vs7.js folder?
There was a problem hiding this comment.
I'm moving them into get-vs2017-path
| home_dot_gyp: homeDotGyp, | ||
| root_targets: options.root_targets, | ||
| target_arch: cmdlineDefaultVariables['target_arch'] || '' | ||
| target_arch: cmdlineDefaultVariables['target_arch'] || 'ia32' |
There was a problem hiding this comment.
Let's talk about why is this necessary. 😉
There was a problem hiding this comment.
So It won't be necessary in every access to conf['target_arch'] later
There was a problem hiding this comment.
Should we put process.arch here then?
e9dee6e to
bd98d01
Compare
| home_dot_gyp: homeDotGyp, | ||
| root_targets: options.root_targets, | ||
| target_arch: cmdlineDefaultVariables['target_arch'] || '' | ||
| target_arch: cmdlineDefaultVariables['target_arch'] || 'ia32' |
There was a problem hiding this comment.
Should we put process.arch here then?
| if (process.platform === 'win32') { | ||
| const getVS2017Path = require('get-vs2017-path').getVS2017Path; | ||
| exports.getVS2017Path = function (hostBits, target_arch) { | ||
| return getVS2017Path(hostBits, target_arch, exports); |
There was a problem hiding this comment.
What is the last argument here for?
There was a problem hiding this comment.
I name it "require less" I use your external bindings (execSync, log, and path)
| targetDict: this.targetDicts[target].configurations[this.config], | ||
| ninjas: ninjas, | ||
| config: this.config | ||
| target, |
There was a problem hiding this comment.
Not that I mind that much, but I still have hopes for transpiling it to ES5 with a minimal AST transformation. Let's keep these changes out for now.
| } | ||
| const env = lines.reduce((s, l) => { | ||
| const kv = l.split('='); | ||
| s[kv[0]] = kv[1]; |
There was a problem hiding this comment.
I just don't want to get any unwanted extras from default global env variables.
50cfd89 to
17e5b8a
Compare
|
we could always test build node with |
| // TODO(indutny): escape quotes in res | ||
| return `cmd.exe /s /c "${res}"`; | ||
| const nw = gyp.platform.win.getNinjaWrapper(this.targetArch); | ||
| return `${nw} cmd.exe /s /c "${res}"`; |
There was a problem hiding this comment.
I lost this at some point during rebasing. Just brought it back...
There was a problem hiding this comment.
RE your TODO: the /s switch takes care of all your " worries.
/S behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
There was a problem hiding this comment.
So res = '" "' works? This will look like nw cmd.exe /s /c " " " "...
There was a problem hiding this comment.
Yep. also res = 'xxx "yyy" zzz'.
as long as res is well formed
There was a problem hiding this comment.
I'm not sure that's well formed (in the sense pasting gaga" "lala in a windows console works), but if it is, it'll work.
Thank god it's not VBScript
There was a problem hiding this comment.
cmd /s /c "xxxxxxxxxx" was meant to be like bash -- xxxxxxxxxxxxxx
|
P.S. https://ci.appveyor.com/project/refack/get-vs2017-path for it to pass, it has to pass |
|
Sorry for delay. I spent some additional time on this and now I realize that there is a problem with using external The I'm afraid, this won't work too well for external module. Do you think there is still a chance of having it here? |
|
I'm ahead of you. Check out line 51 in binding.js, I take all dependencies from you (only need |
|
P.S. IMHO |
indutny
left a comment
There was a problem hiding this comment.
Few very last nits. Good work, mate!
| // TODO(indutny): escape quotes in res | ||
| return `cmd.exe /s /c "${res}"`; | ||
| const nw = gyp.platform.win.getNinjaWrapper(this.targetArch); | ||
| return `${nw} cmd.exe /s /c "${res}"`; |
There was a problem hiding this comment.
So res = '" "' works? This will look like nw cmd.exe /s /c " " " "...
| /******************* late require *******************/ | ||
| const getter = require('get-vs2017-path'); | ||
| // We just need all the binding to be set on `exports` | ||
| getter.setBindings(exports); |
| process.stderr.write(message + '\n'); | ||
| }; | ||
|
|
||
| Object.defineProperty(exports, 'win', {get() { |
There was a problem hiding this comment.
Let's be a bit more verbose: get: function get() {. Also, please put it on separate line and indent properly.
| process.stderr.write(message + '\n'); | ||
| }; | ||
|
|
||
| Object.defineProperty(exports, 'win', {get() { |
There was a problem hiding this comment.
Let's be a bit more verbose: get: function get() {. Also, please put it on separate line and indent properly.
| }; | ||
|
|
||
| Object.defineProperty(exports, 'win', {get() { | ||
| /******************* late require *******************/ |
| root_targets: options.root_targets, | ||
| target_arch: cmdlineDefaultVariables['target_arch'] || '' | ||
| target_arch: cmdlineDefaultVariables['target_arch'] | ||
| || gyp.bindings.process.arch |
| fs.writeFileSync(path.join(outDir, envFile), envBlock); | ||
| return envFile; | ||
| }; | ||
|
|
There was a problem hiding this comment.
Please remove this extra whitespace.
|
TODO: write and integration for GitHub code reviews and WebStorm 😉 initial GraphQL gist |
|
Done |
e552dbf to
f98081e
Compare
|
I renamed my package, and I'm planning on eating more of your Windows specific code. My goal is to generate |
|
@refack yikes, sorry! I forgot about this. Would you care to rebase it? This should mostly involve renaming files from |
|
Sure. |
|
@refack what kind of vote do you need? 😉 |
|
review or say LGTW (vs. the "competing" nodejs/node#11867) |
and harden ninja's `cmd` wrap mechanism
|
Was very easy |
|
Landed in 259294b, thank you for awesome work! |
|
The officially supported vswhere tool is now available as part of the install starting today with Visual Studio 15.2 preview 2: https://blogs.msdn.microsoft.com/heaths/2017/04/21/vswhere-is-now-installed-with-visual-studio-2017/. I hope this helps your scenario. This doesn't fix all the existing installs of VS 2017 but going forward you can now detect the VS install locations and whether C++ tools are available from a scripted environment. |
C:\bin\dev\node\node.exe D:\code\3party\gyp.js\bin\gyp --build Release -Iconfig.gypi -Icommon.gypi -Rnode node.gyp