File: find_vs.h

package info (click to toggle)
mymake 2.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 672 kB
  • sloc: cpp: 5,688; lisp: 300; ansic: 195; sh: 86; makefile: 32
file content (126 lines) | stat: -rw-r--r-- 3,333 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#pragma once

#ifdef _MSC_VER

#include <string>
#include <vector>
#include <sstream>
#include <Windows.h>

#ifndef ARRAY_COUNT
#define ARRAY_COUNT(x) (sizeof(x) / sizeof(*x))
#endif

#pragma comment (lib, "shlwapi.lib")

namespace find_vs {

	using std::vector;
	using std::string;
	using std::istringstream;
	using std::cout;
	using std::endl;

	/**
	 * Utility functions for finding Visual Studio on Windows.
	 *
	 * Include from one cpp-file for each project.
	 */

	// What to look for: It seems "vcvarsall.bat" is always present and works approximately the same across versions.
	const char *toolNames[] = {
		// "VsDevCmd.bat",  // At least on VS2019
		"vcvarsall.bat", // At least on VS2008
	};

	bool isToolFile(const char *file) {
		for (size_t i = 0; i < ARRAY_COUNT(toolNames); i++) {
			if (_stricmp(file, toolNames[i]) == 0)
				return true;
		}
		return false;
	}

	// Find vs files.
	void find(vector<string> &out, const string &root) {
		WIN32_FIND_DATA file;
		HANDLE handle = FindFirstFile((root + "*").c_str(), &file);
		if (handle == INVALID_HANDLE_VALUE)
			return;

		do {
			if (strcmp(file.cFileName, ".") == 0 || strcmp(file.cFileName, "..") == 0) {
				continue;
			} else if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
				find(out, root + file.cFileName + "\\");
			} else if (isToolFile(file.cFileName)) {
				out.push_back(root + file.cFileName);
			}
		} while (FindNextFile(handle, &file) == TRUE);

		FindClose(handle);
	}

	// Pick one out of multiple candidates.
	string pick(const vector<string> &candidates) {
		if (candidates.size() == 1)
			return candidates[0];

		cout << "Multiple versions of Visual Studio were found. Please pick the one you want to use:" << endl;
		for (size_t i = 0; i < candidates.size(); i++)
			cout << (i + 1) << "> " << candidates[i] << endl;

		while (true) {
			cout << "?> ";
			string selection;
			if (!getline(std::cin, selection))
				exit(1);

			istringstream iss(selection);
			size_t id;
			if (!(iss >> id)) {
				cout << "Not a number, try again!" << endl;
				continue;
			}

			if (id > 0 && id <= candidates.size())
				return candidates[id - 1];

			cout << "Not an option, try again!" << endl;
		}
	}

	// Find vs using default heuristics. Provide a hint if desired.
	string find(const string *hint) {
		vector<string> candidates;
		if (hint) {
			DWORD attrs = GetFileAttributes(hint->c_str());
			if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) {
				return *hint;
			} else {
				string name = *hint;
				if (name[name.size() - 1] != '\\')
					name += "\\";
				cout << "Looking for the Visual Studio command line tools in " << name << "..." << endl;
				find(candidates, name);
			}
		} else {
			cout << "Looking for the Visual Studio command line tools..." << endl;
			find(candidates, "C:\\Program Files (x86)\\");
			find(candidates, "C:\\Program Files\\");
		}

		if (candidates.empty()) {
			cout << "Unable to find the Visual Studio command line tools using any of the following names:" << endl;
			for (size_t i = 0; i < ARRAY_COUNT(toolNames); i++)
				cout << "  " << toolNames[i] << endl;
			cout << "Please try specifying either the path to your Visual Studio installation, or the full path to any of the above files." << endl;
			return "";
		}

		return pick(candidates);
	}

}

#endif