15e8470afSJim Cownie /*
25e8470afSJim Cownie * extractExternal.cpp
35e8470afSJim Cownie */
45e8470afSJim Cownie
55e8470afSJim Cownie //===----------------------------------------------------------------------===//
65e8470afSJim Cownie //
757b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
857b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
957b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
105e8470afSJim Cownie //
115e8470afSJim Cownie //===----------------------------------------------------------------------===//
125e8470afSJim Cownie
135e8470afSJim Cownie #include <fstream>
143041982dSJonathan Peyton #include <iostream>
155e8470afSJim Cownie #include <map>
163041982dSJonathan Peyton #include <set>
173041982dSJonathan Peyton #include <stdlib.h>
183041982dSJonathan Peyton #include <string>
193041982dSJonathan Peyton #include <strstream>
205e8470afSJim Cownie
215e8470afSJim Cownie /* Given a set of n object files h ('external' object files) and a set of m
225e8470afSJim Cownie object files o ('internal' object files),
235e8470afSJim Cownie 1. Determines r, the subset of h that o depends on, directly or indirectly
245e8470afSJim Cownie 2. Removes the files in h - r from the file system
255e8470afSJim Cownie 3. For each external symbol defined in some file in r, rename it in r U o
265e8470afSJim Cownie by prefixing it with "__kmp_external_"
275e8470afSJim Cownie Usage:
285e8470afSJim Cownie hide.exe <n> <filenames for h> <filenames for o>
295e8470afSJim Cownie
303041982dSJonathan Peyton Thus, the prefixed symbols become hidden in the sense that they now have a
313041982dSJonathan Peyton special prefix.
325e8470afSJim Cownie */
335e8470afSJim Cownie
345e8470afSJim Cownie using namespace std;
355e8470afSJim Cownie
stop(char * errorMsg)365e8470afSJim Cownie void stop(char *errorMsg) {
375e8470afSJim Cownie printf("%s\n", errorMsg);
385e8470afSJim Cownie exit(1);
395e8470afSJim Cownie }
405e8470afSJim Cownie
415e8470afSJim Cownie // an entry in the symbol table of a .OBJ file
425e8470afSJim Cownie class Symbol {
435e8470afSJim Cownie public:
445e8470afSJim Cownie __int64 name;
455e8470afSJim Cownie unsigned value;
465e8470afSJim Cownie unsigned short sectionNum, type;
475e8470afSJim Cownie char storageClass, nAux;
485e8470afSJim Cownie };
495e8470afSJim Cownie
505e8470afSJim Cownie class _rstream : public istrstream {
515e8470afSJim Cownie private:
525e8470afSJim Cownie const char *buf;
533041982dSJonathan Peyton
545e8470afSJim Cownie protected:
_rstream(pair<const char *,streamsize> p)553041982dSJonathan Peyton _rstream(pair<const char *, streamsize> p)
563041982dSJonathan Peyton : istrstream(p.first, p.second), buf(p.first) {}
~_rstream()573041982dSJonathan Peyton ~_rstream() { delete[] buf; }
585e8470afSJim Cownie };
595e8470afSJim Cownie
60*4c6a098aSKazuaki Ishizaki // A stream encapsulating the content of a file or the content of a string,
613041982dSJonathan Peyton // overriding the >> operator to read various integer types in binary form,
623041982dSJonathan Peyton // as well as a symbol table entry.
635e8470afSJim Cownie class rstream : public _rstream {
645e8470afSJim Cownie private:
doRead(T & x)653041982dSJonathan Peyton template <class T> inline rstream &doRead(T &x) {
665e8470afSJim Cownie read((char *)&x, sizeof(T));
675e8470afSJim Cownie return *this;
685e8470afSJim Cownie }
getBuf(const char * fileName)695e8470afSJim Cownie static pair<const char *, streamsize> getBuf(const char *fileName) {
705e8470afSJim Cownie ifstream raw(fileName, ios::binary | ios::in);
715e8470afSJim Cownie if (!raw.is_open())
725e8470afSJim Cownie stop("rstream.getBuf: Error opening file");
735e8470afSJim Cownie raw.seekg(0, ios::end);
745e8470afSJim Cownie streampos fileSize = raw.tellg();
755e8470afSJim Cownie if (fileSize < 0)
765e8470afSJim Cownie stop("rstream.getBuf: Error reading file");
775e8470afSJim Cownie char *buf = new char[fileSize];
785e8470afSJim Cownie raw.seekg(0, ios::beg);
795e8470afSJim Cownie raw.read(buf, fileSize);
805e8470afSJim Cownie return pair<const char *, streamsize>(buf, fileSize);
815e8470afSJim Cownie }
823041982dSJonathan Peyton
835e8470afSJim Cownie public:
845e8470afSJim Cownie // construct from a string
rstream(const char * buf,streamsize size)853041982dSJonathan Peyton rstream(const char *buf, streamsize size)
863041982dSJonathan Peyton : _rstream(pair<const char *, streamsize>(buf, size)) {}
873041982dSJonathan Peyton // construct from a file whole content is fully read once to initialize the
883041982dSJonathan Peyton // content of this stream
rstream(const char * fileName)895e8470afSJim Cownie rstream(const char *fileName) : _rstream(getBuf(fileName)) {}
operator >>(int & x)903041982dSJonathan Peyton rstream &operator>>(int &x) { return doRead(x); }
operator >>(unsigned & x)913041982dSJonathan Peyton rstream &operator>>(unsigned &x) { return doRead(x); }
operator >>(short & x)923041982dSJonathan Peyton rstream &operator>>(short &x) { return doRead(x); }
operator >>(unsigned short & x)933041982dSJonathan Peyton rstream &operator>>(unsigned short &x) { return doRead(x); }
operator >>(Symbol & e)945e8470afSJim Cownie rstream &operator>>(Symbol &e) {
955e8470afSJim Cownie read((char *)&e, 18);
965e8470afSJim Cownie return *this;
975e8470afSJim Cownie }
985e8470afSJim Cownie };
995e8470afSJim Cownie
1005e8470afSJim Cownie // string table in a .OBJ file
1015e8470afSJim Cownie class StringTable {
1025e8470afSJim Cownie private:
1035e8470afSJim Cownie map<string, unsigned> directory;
1045e8470afSJim Cownie size_t length;
1055e8470afSJim Cownie char *data;
1065e8470afSJim Cownie
1075e8470afSJim Cownie // make <directory> from <length> bytes in <data>
makeDirectory(void)1085e8470afSJim Cownie void makeDirectory(void) {
1095e8470afSJim Cownie unsigned i = 4;
1105e8470afSJim Cownie while (i < length) {
1115e8470afSJim Cownie string s = string(data + i);
1125e8470afSJim Cownie directory.insert(make_pair(s, i));
1135e8470afSJim Cownie i += s.size() + 1;
1145e8470afSJim Cownie }
1155e8470afSJim Cownie }
1165e8470afSJim Cownie // initialize <length> and <data> with contents specified by the arguments
init(const char * _data)1175e8470afSJim Cownie void init(const char *_data) {
1185e8470afSJim Cownie unsigned _length = *(unsigned *)_data;
1195e8470afSJim Cownie
1205e8470afSJim Cownie if (_length < sizeof(unsigned) || _length != *(unsigned *)_data)
1215e8470afSJim Cownie stop("StringTable.init: Invalid symbol table");
1225e8470afSJim Cownie if (_data[_length - 1]) {
1235e8470afSJim Cownie // to prevent runaway strings, make sure the data ends with a zero
1245e8470afSJim Cownie data = new char[length = _length + 1];
1255e8470afSJim Cownie data[_length] = 0;
1265e8470afSJim Cownie } else {
1275e8470afSJim Cownie data = new char[length = _length];
1285e8470afSJim Cownie }
1295e8470afSJim Cownie *(unsigned *)data = length;
13074bf17b8SAndrey Churbanov KMP_MEMCPY(data + sizeof(unsigned), _data + sizeof(unsigned),
1315e8470afSJim Cownie length - sizeof(unsigned));
1325e8470afSJim Cownie makeDirectory();
1335e8470afSJim Cownie }
1343041982dSJonathan Peyton
1355e8470afSJim Cownie public:
StringTable(rstream & f)1365e8470afSJim Cownie StringTable(rstream &f) {
1373041982dSJonathan Peyton // Construct string table by reading from f.
1385e8470afSJim Cownie streampos s;
1395e8470afSJim Cownie unsigned strSize;
1405e8470afSJim Cownie char *strData;
1415e8470afSJim Cownie
1425e8470afSJim Cownie s = f.tellg();
1435e8470afSJim Cownie f >> strSize;
1445e8470afSJim Cownie if (strSize < sizeof(unsigned))
1455e8470afSJim Cownie stop("StringTable: Invalid string table");
1465e8470afSJim Cownie strData = new char[strSize];
1475e8470afSJim Cownie *(unsigned *)strData = strSize;
1485e8470afSJim Cownie // read the raw data into <strData>
1495e8470afSJim Cownie f.read(strData + sizeof(unsigned), strSize - sizeof(unsigned));
1505e8470afSJim Cownie s = f.tellg() - s;
1515e8470afSJim Cownie if (s < strSize)
1525e8470afSJim Cownie stop("StringTable: Unexpected EOF");
1535e8470afSJim Cownie init(strData);
1545e8470afSJim Cownie delete[] strData;
1555e8470afSJim Cownie }
StringTable(const set<string> & strings)1565e8470afSJim Cownie StringTable(const set<string> &strings) {
1573041982dSJonathan Peyton // Construct string table from given strings.
1585e8470afSJim Cownie char *p;
1595e8470afSJim Cownie set<string>::const_iterator it;
1605e8470afSJim Cownie size_t s;
1615e8470afSJim Cownie
1625e8470afSJim Cownie // count required size for data
1633041982dSJonathan Peyton for (length = sizeof(unsigned), it = strings.begin(); it != strings.end();
1643041982dSJonathan Peyton ++it) {
1655e8470afSJim Cownie size_t l = (*it).size();
1665e8470afSJim Cownie
1675e8470afSJim Cownie if (l > (unsigned)0xFFFFFFFF)
1685e8470afSJim Cownie stop("StringTable: String too long");
1695e8470afSJim Cownie if (l > 8) {
1705e8470afSJim Cownie length += l + 1;
1715e8470afSJim Cownie if (length > (unsigned)0xFFFFFFFF)
1725e8470afSJim Cownie stop("StringTable: Symbol table too long");
1735e8470afSJim Cownie }
1745e8470afSJim Cownie }
1755e8470afSJim Cownie data = new char[length];
1765e8470afSJim Cownie *(unsigned *)data = length;
1775e8470afSJim Cownie // populate data and directory
1783041982dSJonathan Peyton for (p = data + sizeof(unsigned), it = strings.begin(); it != strings.end();
1793041982dSJonathan Peyton ++it) {
1805e8470afSJim Cownie const string &str = *it;
1815e8470afSJim Cownie size_t l = str.size();
1825e8470afSJim Cownie if (l > 8) {
1835e8470afSJim Cownie directory.insert(make_pair(str, p - data));
18474bf17b8SAndrey Churbanov KMP_MEMCPY(p, str.c_str(), l);
1855e8470afSJim Cownie p[l] = 0;
1865e8470afSJim Cownie p += l + 1;
1875e8470afSJim Cownie }
1885e8470afSJim Cownie }
1895e8470afSJim Cownie }
~StringTable()1903041982dSJonathan Peyton ~StringTable() { delete[] data; }
1913041982dSJonathan Peyton // Returns encoding for given string based on this string table. Error if
1923041982dSJonathan Peyton // string length is greater than 8 but string is not in the string table
1933041982dSJonathan Peyton // -- returns 0.
encode(const string & str)1945e8470afSJim Cownie __int64 encode(const string &str) {
1955e8470afSJim Cownie __int64 r;
1965e8470afSJim Cownie
1975e8470afSJim Cownie if (str.size() <= 8) {
1985e8470afSJim Cownie // encoded directly
1995e8470afSJim Cownie ((char *)&r)[7] = 0;
20074bf17b8SAndrey Churbanov KMP_STRNCPY_S((char *)&r, sizeof(r), str.c_str(), 8);
2015e8470afSJim Cownie return r;
2025e8470afSJim Cownie } else {
2035e8470afSJim Cownie // represented as index into table
2045e8470afSJim Cownie map<string, unsigned>::const_iterator it = directory.find(str);
2055e8470afSJim Cownie if (it == directory.end())
2065e8470afSJim Cownie stop("StringTable::encode: String now found in string table");
2075e8470afSJim Cownie ((unsigned *)&r)[0] = 0;
2085e8470afSJim Cownie ((unsigned *)&r)[1] = (*it).second;
2095e8470afSJim Cownie return r;
2105e8470afSJim Cownie }
2115e8470afSJim Cownie }
2123041982dSJonathan Peyton // Returns string represented by x based on this string table. Error if x
2133041982dSJonathan Peyton // references an invalid position in the table--returns the empty string.
decode(__int64 x) const2145e8470afSJim Cownie string decode(__int64 x) const {
2155e8470afSJim Cownie if (*(unsigned *)&x == 0) {
2165e8470afSJim Cownie // represented as index into table
2175e8470afSJim Cownie unsigned &p = ((unsigned *)&x)[1];
2185e8470afSJim Cownie if (p >= length)
2195e8470afSJim Cownie stop("StringTable::decode: Invalid string table lookup");
2205e8470afSJim Cownie return string(data + p);
2215e8470afSJim Cownie } else {
2225e8470afSJim Cownie // encoded directly
2235e8470afSJim Cownie char *p = (char *)&x;
2245e8470afSJim Cownie int i;
2255e8470afSJim Cownie
2263041982dSJonathan Peyton for (i = 0; i < 8 && p[i]; ++i)
2273041982dSJonathan Peyton ;
2285e8470afSJim Cownie return string(p, i);
2295e8470afSJim Cownie }
2305e8470afSJim Cownie }
write(ostream & os)2313041982dSJonathan Peyton void write(ostream &os) { os.write(data, length); }
2325e8470afSJim Cownie };
2335e8470afSJim Cownie
2343041982dSJonathan Peyton // for the named object file, determines the set of defined symbols and the set
2353041982dSJonathan Peyton // of undefined external symbols and writes them to <defined> and <undefined>
2363041982dSJonathan Peyton // respectively
computeExternalSymbols(const char * fileName,set<string> * defined,set<string> * undefined)2373041982dSJonathan Peyton void computeExternalSymbols(const char *fileName, set<string> *defined,
2383041982dSJonathan Peyton set<string> *undefined) {
2395e8470afSJim Cownie streampos fileSize;
2405e8470afSJim Cownie size_t strTabStart;
2415e8470afSJim Cownie unsigned symTabStart, symNEntries;
2425e8470afSJim Cownie rstream f(fileName);
2435e8470afSJim Cownie
2445e8470afSJim Cownie f.seekg(0, ios::end);
2455e8470afSJim Cownie fileSize = f.tellg();
2465e8470afSJim Cownie
2475e8470afSJim Cownie f.seekg(8);
2485e8470afSJim Cownie f >> symTabStart >> symNEntries;
2495e8470afSJim Cownie // seek to the string table
2505e8470afSJim Cownie f.seekg(strTabStart = symTabStart + 18 * (size_t)symNEntries);
2515e8470afSJim Cownie if (f.eof()) {
2523041982dSJonathan Peyton printf("computeExternalSymbols: fileName='%s', fileSize = %lu, symTabStart "
2533041982dSJonathan Peyton "= %u, symNEntries = %u\n",
2545e8470afSJim Cownie fileName, (unsigned long)fileSize, symTabStart, symNEntries);
2555e8470afSJim Cownie stop("computeExternalSymbols: Unexpected EOF 1");
2565e8470afSJim Cownie }
2575e8470afSJim Cownie StringTable stringTable(f); // read the string table
2585e8470afSJim Cownie if (f.tellg() != fileSize)
2595e8470afSJim Cownie stop("computeExternalSymbols: Unexpected data after string table");
2605e8470afSJim Cownie
2615e8470afSJim Cownie f.clear();
2625e8470afSJim Cownie f.seekg(symTabStart); // seek to the symbol table
2635e8470afSJim Cownie
2643041982dSJonathan Peyton defined->clear();
2653041982dSJonathan Peyton undefined->clear();
2665e8470afSJim Cownie for (int i = 0; i < symNEntries; ++i) {
2675e8470afSJim Cownie // process each entry
2685e8470afSJim Cownie Symbol e;
2695e8470afSJim Cownie
2705e8470afSJim Cownie if (f.eof())
2715e8470afSJim Cownie stop("computeExternalSymbols: Unexpected EOF 2");
2725e8470afSJim Cownie f >> e;
2735e8470afSJim Cownie if (f.fail())
2745e8470afSJim Cownie stop("computeExternalSymbols: File read error");
2755e8470afSJim Cownie if (e.nAux) { // auxiliary entry: skip
2765e8470afSJim Cownie f.seekg(e.nAux * 18, ios::cur);
2775e8470afSJim Cownie i += e.nAux;
2785e8470afSJim Cownie }
2795e8470afSJim Cownie // if symbol is extern and defined in the current file, insert it
2805e8470afSJim Cownie if (e.storageClass == 2)
2815e8470afSJim Cownie if (e.sectionNum)
2825e8470afSJim Cownie defined->insert(stringTable.decode(e.name));
2835e8470afSJim Cownie else
2845e8470afSJim Cownie undefined->insert(stringTable.decode(e.name));
2855e8470afSJim Cownie }
2865e8470afSJim Cownie }
2875e8470afSJim Cownie
2883041982dSJonathan Peyton // For each occurrence of an external symbol in the object file named by
2893041982dSJonathan Peyton // by <fileName> that is a member of <hide>, renames it by prefixing
2903041982dSJonathan Peyton // with "__kmp_external_", writing back the file in-place
hideSymbols(char * fileName,const set<string> & hide)2915e8470afSJim Cownie void hideSymbols(char *fileName, const set<string> &hide) {
2925e8470afSJim Cownie static const string prefix("__kmp_external_");
2935e8470afSJim Cownie set<string> strings; // set of all occurring symbols, appropriately prefixed
2945e8470afSJim Cownie streampos fileSize;
2955e8470afSJim Cownie size_t strTabStart;
2965e8470afSJim Cownie unsigned symTabStart, symNEntries;
2975e8470afSJim Cownie int i;
2985e8470afSJim Cownie rstream in(fileName);
2995e8470afSJim Cownie
3005e8470afSJim Cownie in.seekg(0, ios::end);
3015e8470afSJim Cownie fileSize = in.tellg();
3025e8470afSJim Cownie
3035e8470afSJim Cownie in.seekg(8);
3045e8470afSJim Cownie in >> symTabStart >> symNEntries;
3055e8470afSJim Cownie in.seekg(strTabStart = symTabStart + 18 * (size_t)symNEntries);
3065e8470afSJim Cownie if (in.eof())
3075e8470afSJim Cownie stop("hideSymbols: Unexpected EOF");
3085e8470afSJim Cownie StringTable stringTableOld(in); // read original string table
3095e8470afSJim Cownie
3105e8470afSJim Cownie if (in.tellg() != fileSize)
3115e8470afSJim Cownie stop("hideSymbols: Unexpected data after string table");
3125e8470afSJim Cownie
3135e8470afSJim Cownie // compute set of occurring strings with prefix added
3145e8470afSJim Cownie for (i = 0; i < symNEntries; ++i) {
3155e8470afSJim Cownie Symbol e;
3165e8470afSJim Cownie
3175e8470afSJim Cownie in.seekg(symTabStart + i * 18);
3185e8470afSJim Cownie if (in.eof())
3195e8470afSJim Cownie stop("hideSymbols: Unexpected EOF");
3205e8470afSJim Cownie in >> e;
3215e8470afSJim Cownie if (in.fail())
3225e8470afSJim Cownie stop("hideSymbols: File read error");
3235e8470afSJim Cownie if (e.nAux)
3245e8470afSJim Cownie i += e.nAux;
3255e8470afSJim Cownie const string &s = stringTableOld.decode(e.name);
3265e8470afSJim Cownie // if symbol is extern and found in <hide>, prefix and insert into strings,
3275e8470afSJim Cownie // otherwise, just insert into strings without prefix
3283041982dSJonathan Peyton strings.insert(
3293041982dSJonathan Peyton (e.storageClass == 2 && hide.find(s) != hide.end()) ? prefix + s : s);
3305e8470afSJim Cownie }
3315e8470afSJim Cownie
3325e8470afSJim Cownie ofstream out(fileName, ios::trunc | ios::out | ios::binary);
3335e8470afSJim Cownie if (!out.is_open())
3345e8470afSJim Cownie stop("hideSymbols: Error opening output file");
3355e8470afSJim Cownie
3365e8470afSJim Cownie // make new string table from string set
3375e8470afSJim Cownie StringTable stringTableNew = StringTable(strings);
3385e8470afSJim Cownie
3395e8470afSJim Cownie // copy input file to output file up to just before the symbol table
3405e8470afSJim Cownie in.seekg(0);
3415e8470afSJim Cownie char *buf = new char[symTabStart];
3425e8470afSJim Cownie in.read(buf, symTabStart);
3435e8470afSJim Cownie out.write(buf, symTabStart);
3445e8470afSJim Cownie delete[] buf;
3455e8470afSJim Cownie
3465e8470afSJim Cownie // copy input symbol table to output symbol table with name translation
3475e8470afSJim Cownie for (i = 0; i < symNEntries; ++i) {
3485e8470afSJim Cownie Symbol e;
3495e8470afSJim Cownie
3505e8470afSJim Cownie in.seekg(symTabStart + i * 18);
3515e8470afSJim Cownie if (in.eof())
3525e8470afSJim Cownie stop("hideSymbols: Unexpected EOF");
3535e8470afSJim Cownie in >> e;
3545e8470afSJim Cownie if (in.fail())
3555e8470afSJim Cownie stop("hideSymbols: File read error");
3565e8470afSJim Cownie const string &s = stringTableOld.decode(e.name);
3575e8470afSJim Cownie out.seekp(symTabStart + i * 18);
3583041982dSJonathan Peyton e.name = stringTableNew.encode(
3593041982dSJonathan Peyton (e.storageClass == 2 && hide.find(s) != hide.end()) ? prefix + s : s);
3605e8470afSJim Cownie out.write((char *)&e, 18);
3615e8470afSJim Cownie if (out.fail())
3625e8470afSJim Cownie stop("hideSymbols: File write error");
3635e8470afSJim Cownie if (e.nAux) {
3645e8470afSJim Cownie // copy auxiliary symbol table entries
3655e8470afSJim Cownie int nAux = e.nAux;
3665e8470afSJim Cownie for (int j = 1; j <= nAux; ++j) {
3675e8470afSJim Cownie in >> e;
3685e8470afSJim Cownie out.seekp(symTabStart + (i + j) * 18);
3695e8470afSJim Cownie out.write((char *)&e, 18);
3705e8470afSJim Cownie }
3715e8470afSJim Cownie i += nAux;
3725e8470afSJim Cownie }
3735e8470afSJim Cownie }
3745e8470afSJim Cownie // output string table
3755e8470afSJim Cownie stringTableNew.write(out);
3765e8470afSJim Cownie }
3775e8470afSJim Cownie
3785e8470afSJim Cownie // returns true iff <a> and <b> have no common element
isDisjoint(const set<T> & a,const set<T> & b)3793041982dSJonathan Peyton template <class T> bool isDisjoint(const set<T> &a, const set<T> &b) {
3805e8470afSJim Cownie set<T>::const_iterator ita, itb;
3815e8470afSJim Cownie
3825e8470afSJim Cownie for (ita = a.begin(), itb = b.begin(); ita != a.end() && itb != b.end();) {
3835e8470afSJim Cownie const T &ta = *ita, &tb = *itb;
3845e8470afSJim Cownie if (ta < tb)
3855e8470afSJim Cownie ++ita;
3865e8470afSJim Cownie else if (tb < ta)
3875e8470afSJim Cownie ++itb;
3885e8470afSJim Cownie else
3895e8470afSJim Cownie return false;
3905e8470afSJim Cownie }
3915e8470afSJim Cownie return true;
3925e8470afSJim Cownie }
3935e8470afSJim Cownie
3943041982dSJonathan Peyton // PRE: <defined> and <undefined> are arrays with <nTotal> elements where
3953041982dSJonathan Peyton // <nTotal> >= <nExternal>. The first <nExternal> elements correspond to the
3963041982dSJonathan Peyton // external object files and the rest correspond to the internal object files.
3973041982dSJonathan Peyton // POST: file x is said to depend on file y if undefined[x] and defined[y] are
3983041982dSJonathan Peyton // not disjoint. Returns the transitive closure of the set of internal object
3993041982dSJonathan Peyton // files, as a set of file indexes, under the 'depends on' relation, minus the
4003041982dSJonathan Peyton // set of internal object files.
findRequiredExternal(int nExternal,int nTotal,set<string> * defined,set<string> * undefined)4013041982dSJonathan Peyton set<int> *findRequiredExternal(int nExternal, int nTotal, set<string> *defined,
4023041982dSJonathan Peyton set<string> *undefined) {
4035e8470afSJim Cownie set<int> *required = new set<int>;
4045e8470afSJim Cownie set<int> fresh[2];
4055e8470afSJim Cownie int i, cur = 0;
4065e8470afSJim Cownie bool changed;
4075e8470afSJim Cownie
4085e8470afSJim Cownie for (i = nTotal - 1; i >= nExternal; --i)
4095e8470afSJim Cownie fresh[cur].insert(i);
4105e8470afSJim Cownie do {
4115e8470afSJim Cownie changed = false;
4123041982dSJonathan Peyton for (set<int>::iterator it = fresh[cur].begin(); it != fresh[cur].end();
4133041982dSJonathan Peyton ++it) {
4145e8470afSJim Cownie set<string> &s = undefined[*it];
4155e8470afSJim Cownie
4165e8470afSJim Cownie for (i = 0; i < nExternal; ++i) {
4175e8470afSJim Cownie if (required->find(i) == required->end()) {
4185e8470afSJim Cownie if (!isDisjoint(defined[i], s)) {
4195e8470afSJim Cownie // found a new qualifying element
4205e8470afSJim Cownie required->insert(i);
4215e8470afSJim Cownie fresh[1 - cur].insert(i);
4225e8470afSJim Cownie changed = true;
4235e8470afSJim Cownie }
4245e8470afSJim Cownie }
4255e8470afSJim Cownie }
4265e8470afSJim Cownie }
4275e8470afSJim Cownie fresh[cur].clear();
4285e8470afSJim Cownie cur = 1 - cur;
4295e8470afSJim Cownie } while (changed);
4305e8470afSJim Cownie return required;
4315e8470afSJim Cownie }
4325e8470afSJim Cownie
main(int argc,char ** argv)4335e8470afSJim Cownie int main(int argc, char **argv) {
4345e8470afSJim Cownie int nExternal, nInternal, i;
4355e8470afSJim Cownie set<string> *defined, *undefined;
4365e8470afSJim Cownie set<int>::iterator it;
4375e8470afSJim Cownie
4385e8470afSJim Cownie if (argc < 3)
4393041982dSJonathan Peyton stop("Please specify a positive integer followed by a list of object "
4403041982dSJonathan Peyton "filenames");
4415e8470afSJim Cownie nExternal = atoi(argv[1]);
4425e8470afSJim Cownie if (nExternal <= 0)
4433041982dSJonathan Peyton stop("Please specify a positive integer followed by a list of object "
4443041982dSJonathan Peyton "filenames");
4455e8470afSJim Cownie if (nExternal + 2 > argc)
4465e8470afSJim Cownie stop("Too few external objects");
4475e8470afSJim Cownie nInternal = argc - nExternal - 2;
4485e8470afSJim Cownie defined = new set<string>[argc - 2];
4495e8470afSJim Cownie undefined = new set<string>[argc - 2];
4505e8470afSJim Cownie
4515e8470afSJim Cownie // determine the set of defined and undefined external symbols
4525e8470afSJim Cownie for (i = 2; i < argc; ++i)
4535e8470afSJim Cownie computeExternalSymbols(argv[i], defined + i - 2, undefined + i - 2);
4545e8470afSJim Cownie
4555e8470afSJim Cownie // determine the set of required external files
4563041982dSJonathan Peyton set<int> *requiredExternal =
4573041982dSJonathan Peyton findRequiredExternal(nExternal, argc - 2, defined, undefined);
4585e8470afSJim Cownie set<string> hide;
4595e8470afSJim Cownie
4603041982dSJonathan Peyton // determine the set of symbols to hide--namely defined external symbols of
4613041982dSJonathan Peyton // the required external files
4625e8470afSJim Cownie for (it = requiredExternal->begin(); it != requiredExternal->end(); ++it) {
4635e8470afSJim Cownie int idx = *it;
4645e8470afSJim Cownie set<string>::iterator it2;
4653041982dSJonathan Peyton // We have to insert one element at a time instead of inserting a range
4663041982dSJonathan Peyton // because the insert member function taking a range doesn't exist on
4673041982dSJonathan Peyton // Windows* OS, at least at the time of this writing.
4685e8470afSJim Cownie for (it2 = defined[idx].begin(); it2 != defined[idx].end(); ++it2)
4695e8470afSJim Cownie hide.insert(*it2);
4705e8470afSJim Cownie }
4715e8470afSJim Cownie
4723041982dSJonathan Peyton // process the external files--removing those that are not required and hiding
4733041982dSJonathan Peyton // the appropriate symbols in the others
4745e8470afSJim Cownie for (i = 0; i < nExternal; ++i)
4755e8470afSJim Cownie if (requiredExternal->find(i) != requiredExternal->end())
4765e8470afSJim Cownie hideSymbols(argv[2 + i], hide);
4775e8470afSJim Cownie else
4785e8470afSJim Cownie remove(argv[2 + i]);
4795e8470afSJim Cownie // hide the appropriate symbols in the internal files
4805e8470afSJim Cownie for (i = nExternal + 2; i < argc; ++i)
4815e8470afSJim Cownie hideSymbols(argv[i], hide);
4825e8470afSJim Cownie return 0;
4835e8470afSJim Cownie }
484