Sonar looks for build-wrapper even though it hasn't been configured

The cl.exe path that is used is using windows short-path (PROGRAM~2) and that may be also the cause of the issue. They could be eliminated by expanding cmd[0] in convert-compile-commands.py, before generating the entry. One options is to use win32file.GetLongPathName() from pywin32.

great! will try that. What about slashes in the options? I think I remember that they were escaped in the original buildwrapper output but not in the python output. Do you think it makes sense to output \/Gy
for example?

If the short-path correction is not causing the issue, could you please share the updated build-wrapper.json file and the sonar scanner log privately?

@michael-brade,
After investing your build-wrapper-dump.json file and the 8.9 LTS requirements, I have found out that for MSVC we need one additional entry in the capture list. This entry should be at the beginning of the list and have format:

{
"compiler":"msvc-cl",
"executable": *path to the compiler executable*,
"stdout": *output of the invocation to stdout*,
"stderr": *output of the invocation to stderr*
}

Also, would it be possible to share your version of the python script for conversion on the forum? It may be useful for other people visiting a forum.

1 Like

Yes, thank you! That did it. So here is my updated python script:

"""
#
# Warning:
#  - This is a workaround for builds where build-wrapper doesn't work
#  - This is only for msvc
"""

import sys
import json
import shlex
from collections import OrderedDict
import os
import ctypes
import subprocess

def getLongPathName(path):
  buf = ctypes.create_unicode_buffer(260)
  GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
  rv = GetLongPathName(path, buf, 260)
  if rv == 0 or rv > 260:
    return path
  else:
    return buf.value


if len(sys.argv) < 2:
  sys.stderr.write("Usage: %s <path to compile_commands.json>\n" % (sys.argv[0]))
  sys.exit(1)

with open(sys.argv[1]) as db_file:
  db = json.load(db_file)

env = []
for k, v in os.environ.items():
  env.append("%s=%s" % (k, v))

captures = []

compiler_capt = OrderedDict()
compiler_capt['compiler'] = "msvc-cl"
compiler_capt['executable'] = ""
compiler_capt['stdout'] = ""
compiler_capt['stderr'] = ""

captures.append(compiler_capt)

for entry in db:
  if 'arguments' in entry:
    cmd = entry['arguments']
  else:
    # we need to remove the ' at the beginning and the end of the string before splitting it
    cmd = shlex.quote(entry['command'])[1:-1].split()

  # rc.exe entries are not needed for sonar
  if cmd[0].endswith('rc.exe'):
    continue

  cmd[0] = getLongPathName(cmd[0])

  capture = OrderedDict()
  capture['compiler'] = 'msvc-cl'
  capture['cwd'] = entry['directory']
  capture['executable'] = cmd[0]
  capture['cmd'] = cmd
  capture['env'] = env
  captures.append(capture)


result = subprocess.run(captures[1]['executable'], capture_output=True)

captures[0]['executable'] = captures[1]['executable']
captures[0]['stdout'] = result.stdout.decode('cp850')
captures[0]['stderr'] = result.stderr.decode('cp850')

bw = OrderedDict()
bw['version'] = 0
bw['captures'] = captures

os.makedirs('bw-outputs', exist_ok=True)
with open('bw-outputs/build-wrapper-dump.json', 'w') as bw_file:
  json.dump(bw, bw_file, indent = 2)
print('File created: bw-outputs/build-wrapper-dump.json')

Maybe the conversion to long path names is not actually needed, maybe rc.exe could be left in the dump – I didn’t test that because it works now :innocent: You will have to call it from Jenkinsfile like this:

	bat """
	    set path=%path:"=%
		call "${env.VS_VCVARS}"
		python.exe convert-compile-commands.py build\\compile_commands.json
	"""