protected static Int32 ConvertTypeToInt(IncludeDirectoryType type)
        {
            switch (type)
            {
            case IncludeDirectoryType.Quote: return(10);

            case IncludeDirectoryType.Generic: return(20);

            case IncludeDirectoryType.System: return(30);

            case IncludeDirectoryType.DirAfter: return(40);

            default: {
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
            }
        }
 public IncludeDirectory(AbsoluteCrosspath path, IncludeDirectoryType type) : base(path)
 {
     Type      = type;
     ShortName = $"{serial:D4}";
     ++serial;
 }
        /// <summary>
        /// Call RemoteHost.ExtractInfoFromCompiler() instead.
        /// Requires these utilities on the remote system: pwd, echo, which, touch, sort, pushd, popd, zip
        /// </summary>
        /// <param name="remote">Remote host where compiler installed</param>
        public void ExtractAdditionalInfo(RemoteHost remote)
        {
            String remoteTempFile = String.Format(Compiler.RemoteTempFile, BaseCompiler.ShortName, instanceGuid.ToString());

            if (remote.Execute("pwd || echo $PWD", out String pwd) != RemoteHost.Success)
            {
                throw new ApplicationException("could not get current directory name");
            }
            pwd = pwd.TrimEnd(RemoteHost.LineEndingChars);

            if (remote.Execute($"which {BaseCompiler.ExePath}", out String absExePath) != RemoteHost.Success)
            {
                throw new ApplicationException("could not get absolute compiler path");
            }
            absExePath = absExePath.TrimEnd(RemoteHost.LineEndingChars);

            if (remote.Execute($"{BaseCompiler.ExePath} -dumpversion", out String version) != RemoteHost.Success)
            {
                throw new ApplicationException("could not extract version from compiler");
            }
            Version = version.TrimEnd(RemoteHost.LineEndingChars);

            // create temporary .c file for auto-distinguishment between C and C++
            if (remote.Execute($"touch {remoteTempFile} || echo > {remoteTempFile}", out String _) != RemoteHost.Success)
            {
                throw new ApplicationException("could not create temporary file");
            }

            if (remote.Execute($"{BaseCompiler.ExePath} {this} -E -dM {remoteTempFile} | sort", out String defines) != RemoteHost.Success)
            {
                throw new ApplicationException("could not extract defines from compiler");
            }

            if (remote.Execute($"{BaseCompiler.ExePath} {this} -E -Wp,-v {remoteTempFile} 2>&1 1> /dev/null", out String includeDirs) != RemoteHost.Success)
            {
                throw new ApplicationException("could not extract include dirs from compiler");
            }

            AbsoluteCrosspath xpwd      = AbsoluteCrosspath.FromString(pwd);
            AbsoluteCrosspath xcompiler = AbsoluteCrosspath.FromString(absExePath);

            if (!xcompiler.ToString().Equals(BaseCompiler.ExePath.ToString()))
            {
                AbsoluteCrosspath compilerLocatedIn = new AbsoluteCrosspath(xcompiler);
                ((RelativeCrosspath)BaseCompiler.ExePath).SetWorkingDirectory(xcompiler.ToContainingDirectory());
                Logger.WriteLine(LogLevel.Info, $"compiler '{BaseCompiler.ExePath}' actually located at '{xcompiler}'");
            }

            Defines.Clear();
            Platform fallbackPlatform = Platform.x64;

            foreach (String macro in defines.Split(RemoteHost.LineEndings, StringSplitOptions.RemoveEmptyEntries))
            {
                // assuming standard format '#define MACRO some thing probably with spaces'
                String[] defArray = macro.Split(new[] { ' ' }, 3);
                // try to auto-detect the platform
                if (VSPlatform == Platform.Unknown)
                {
                    switch (defArray[1])
                    {
                    case "__x86_64__": VSPlatform = Platform.x64; break;

                    case "__i386__": VSPlatform = Platform.x86; break;

                    case "__arm__": VSPlatform = Platform.ARM; break;

                    case "__aarch64__": VSPlatform = Platform.ARM64; break;

                    case "__mips__": VSPlatform = Platform.MIPS; break;

                    case "__WORDSIZE__":     /* this seems to be standard */
                    case "__INTPTR_WIDTH__": /* this not, but use as fallback */
                        if (Int32.Parse(defArray[2]) == 32)
                        {
                            fallbackPlatform = Platform.x86;
                        }
                        break;
                    }
                }
                Defines.Add(new Define(defArray[1], defArray[2]));
            }
            if (VSPlatform == Platform.Unknown)
            {
                VSPlatform = fallbackPlatform;
            }

            IncludeDirectories.Clear();
            IncludeDirectoryType incDirType = IncludeDirectoryType.Null;

            foreach (String cppLine in includeDirs.Split(RemoteHost.LineEndings, StringSplitOptions.RemoveEmptyEntries))
            {
                // sample output:

/*
 * ignoring nonexistent directory "/opt/gcc-4.1.2-glibc-2.5-binutils-2.17-kernel-2.6.18/arm-v5te-linux-gnueabi/include"
 #include "..." search starts here:
 #include <...> search starts here:
 * /opt/gcc-4.1.2-glibc-2.5-binutils-2.17-kernel-2.6.18/bin/../lib/gcc/arm-v5te-linux-gnueabi/4.1.2/include
 * /opt/gcc-4.1.2-glibc-2.5-binutils-2.17-kernel-2.6.18/bin/../sysroot-arm-v5te-linux-gnueabi/usr/include
 * End of search list.
 */
                // regarding priority:
                // -iquote has the highest priority affecting #include "..." not only #include <...>
                // -I has lower priority than -iquote
                // -isystem has lower priority but yet higher priority than system-wide headers
                //   then follows the priority of system-wide-headers
                // -idirafter has the lowest priority possible
                // example (gcc 9):

/*
 * $ gcc -x c -c -Wp,-v -iquote /proc/1 -I /proc/10 -isystem /proc/12 -I /proc/14 -idirafter /proc/1204 - < /dev/null
 * ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
 * ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"
 * ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"
 #include "..." search starts here:
 * /proc/1
 #include <...> search starts here:
 * /proc/10
 * /proc/14
 * /proc/12
 * /usr/lib/gcc/x86_64-linux-gnu/9/include
 * /usr/local/include
 * /usr/include/x86_64-linux-gnu
 * /usr/include
 * /proc/1204
 * End of search list.
 */
                // usually gcc does not have any include directories in the #include "..." section.
                // so the reason for parsing this section is when using some compiler wrapper that puts some paths to -iquote.
                if (cppLine == "#include \"...\" search starts here:")
                {
                    incDirType = IncludeDirectoryType.Quote;
                    continue;
                }
                if (cppLine == "#include <...> search starts here:")
                {
                    incDirType = IncludeDirectoryType.System;
                    continue;
                }

                if (cppLine.Length > 0 && cppLine[0] == ' ')
                {
                    Crosspath xpath = Crosspath.FromString(cppLine.Substring(1));
                    if (xpath is RelativeCrosspath relPath)
                    {
                        relPath.SetWorkingDirectory(xpwd);
                        xpath = relPath.Absolutized();
                    }
                    IncludeDirectory incDir       = new IncludeDirectory(xpath as AbsoluteCrosspath, incDirType);
                    IncludeDirectory incDirCached = BaseCompiler.TrackIncludeDir(incDir);
                    if (incDirCached != null)
                    {
                        incDir = incDirCached;
                    }
                    IncludeDirectories.Add(incDir);

                    continue;
                }

                if (cppLine == "End of search list.")
                {
                    break;
                }
            }

            HaveAdditionalInfo = true;

            Logger.WriteLine(LogLevel.Info, $"{absExePath} {this} is {VSPlatform} compiler");
        }
        public void AddInfoFromCommandLine(AbsoluteCrosspath workingDir, List <String> args)
        {
            // parse arguments to obtain all -I, -D, -U
            // start from 1 to skip compiler name
            for (Int32 i = 1; i < args.Count; i++)
            {
                // includes:
                // -I
                // -iquote
                // -isystem
                // -idirafter
                // ..., see https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html
                // TODO: also process -nostdinc to control whether system include dirs should be added or not.
                // TODO: preserve priority between -I, -iquote and other include dir types
                IncludeDirectoryType idt = IncludeDirectoryType.Null;
                String includeDirStr     = String.Empty;
                foreach (IncludeDirectoryType idk in IncludeDirectory.IncludeParam.Keys)
                {
                    if (TakeParamValue(args, ref i, IncludeDirectory.IncludeParam[idk], out includeDirStr))
                    {
                        idt = idk;
                        break;
                    }
                }

                if (idt != IncludeDirectoryType.Null)
                {
                    // DONE: determine more accurately which include is local and which is remote
                    // this is done with the use of Solution.Rebase() so we customly point to local files
                    AbsoluteCrosspath includeDirPath = AbsoluteCrosspath.FromString(includeDirStr, workingDir);
                    IncludeDirectory  includeDir     = OwnerSolution.TrackIncludeDirectory(includeDirPath, idt);

                    // relax if we're adding the same include directory twice
                    // TODO: rewrite this using PriorityQueue to preserver order
                    this.AddIncludeDir(includeDir);

                    continue;
                }

                // defines:
                // -D
                if (TakeParamValue(args, ref i, "-D", out String defineString))
                {
                    this.SetCppDefine(defineString);
                    Logger.WriteLine(LogLevel.Trace, $"[i] Added -D{defineString}");
                    continue;
                }

                // undefines:
                // -U
                if (TakeParamValue(args, ref i, "-U", out String undefineString))
                {
                    this.UnsetCppDefine(undefineString);
                    Logger.WriteLine(LogLevel.Trace, $"[i] Added -U{undefineString}");
                    continue;
                }

                if (TakeParamValue(args, ref i, "-include", out String forceInclude))
                {
                    AbsoluteCrosspath forceIncludePath        = AbsoluteCrosspath.FromString(forceInclude, workingDir);
                    ProjectFile       forceIncludeProjectFile = this.OwnerSolution.TrackFile(new ProjectFile(OwnerSolution, forceIncludePath, this.CompilerOfFile), true);
                    this.ForceIncludes.Add(forceIncludeProjectFile.FilePath);
                    // ReSharper disable once RedundantJumpStatement
                    continue;
                }
            }
        }
Exemple #5
0
        internal IncludeDirectory TrackIncludeDirectory(AbsoluteCrosspath includeDirPath, IncludeDirectoryType idt)
        {
            String           includeDirStrReconstructed = includeDirPath.ToString();
            IncludeDirectory includeDir;

            if (!solutionIncludeDirectories.ContainsKey(includeDirStrReconstructed))
            {
                includeDir = new IncludeDirectory(includeDirPath, idt);
                solutionIncludeDirectories.Add(includeDirStrReconstructed, includeDir);
                Logger.WriteLine(LogLevel.Debug, $"New include directory '{includeDirStrReconstructed}'");
            }
            else
            {
                // if this include directory is already known, then drop current object and get old reference
                includeDir = solutionIncludeDirectories[includeDirStrReconstructed];
                Logger.WriteLine(LogLevel.Trace, $"Reusing include directory '{includeDirStrReconstructed}'");
            }

            return(includeDir);
        }