2
This program is free software; you can redistribute it and/or modify
3
it under the terms of the GNU General Public License as published by
4
the Free Software Foundation; either version 2 of the License, or
5
(at your option) any later version.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License along
13
with this program; if not, write to the Free Software Foundation, Inc.,
14
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
#include "Dependency.h"
20
#include <sys/param.h>
28
std::string stripPrefix(std::string in)
30
return in.substr(in.rfind("/")+1);
33
//the pathes to search for dylibs, store it globally to parse the environment variables only once
34
std::vector<std::string> pathes;
36
//initialize the dylib search pathes
37
void initSearchPathes(){
38
//Check the same pathes the system would search for dylibs
39
std::string searchPathes;
40
char *dyldLibPath = std::getenv("DYLD_LIBRARY_PATH");
42
searchPathes = dyldLibPath;
43
dyldLibPath = std::getenv("DYLD_FALLBACK_FRAMEWORK_PATH");
46
if (!searchPathes.empty() && searchPathes[ searchPathes.size()-1 ] != ':') searchPathes += ":";
47
searchPathes += dyldLibPath;
49
dyldLibPath = std::getenv("DYLD_FALLBACK_LIBRARY_PATH");
52
if (!searchPathes.empty() && searchPathes[ searchPathes.size()-1 ] != ':') searchPathes += ":";
53
searchPathes += dyldLibPath;
55
if (!searchPathes.empty())
57
std::stringstream ss(searchPathes);
59
while(std::getline(ss, item, ':'))
61
if (item[ item.size()-1 ] != '/') item += "/";
62
pathes.push_back(item);
67
// if some libs are missing prefixes, this will be set to true
68
// more stuff will then be necessary to do
69
bool missing_prefixes = false;
71
Dependency::Dependency(std::string path)
73
// check if given path is a symlink
74
std::string cmd = "readlink -n " + path;
75
const bool is_symlink = system( (cmd+" > /dev/null").c_str())==0;
78
char original_file_buffer[PATH_MAX];
79
std::string original_file;
81
if (not realpath(path.c_str(), original_file_buffer))
83
std::cerr << "\n/!\\ WARNING : Cannot resolve symlink '" << path.c_str() << "'" << std::endl;
88
original_file = original_file_buffer;
90
//original_file = original_file.substr(0, original_file.find("\n") );
92
filename = stripPrefix(original_file);
93
prefix = path.substr(0, path.rfind("/")+1);
98
filename = stripPrefix(path);
99
prefix = path.substr(0, path.rfind("/")+1);
102
//check if the lib is in a known location
103
if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/";
104
if( prefix.empty() || !fileExists( prefix+filename ) )
106
//the pathes contains at least /usr/lib so if it is empty we have not initilazed it
107
if( pathes.empty() ) initSearchPathes();
109
//check if file is contained in one of the pathes
110
for( size_t i=0; i<pathes.size(); ++i)
112
if (fileExists( pathes[i]+filename ))
114
std::cout << "FOUND " << filename << " in " << pathes[i] << std::endl;
116
missing_prefixes = true; //the prefix was missing
122
//If the location is still unknown, ask the user for search path
123
if( prefix.empty() || !fileExists( prefix+filename ) )
125
std::cerr << "\n/!\\ WARNING : Library " << filename << " has an incomplete name (location unknown)" << std::endl;
126
missing_prefixes = true;
130
std::cout << "Please specify now where this library can be found (or write 'quit' to abort): "; fflush(stdout);
135
std::cout << std::endl;
137
if(prefix.compare("quit")==0) exit(1);
139
if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/";
141
if( !fileExists( prefix+filename ) )
143
std::cerr << (prefix+filename) << " does not exist. Try again" << std::endl;
148
pathes.push_back( prefix );
149
std::cerr << (prefix+filename) << " was found. /!\\MANUALLY CHECK THE EXECUTABLE WITH 'otool -L', DYLIBBUNDLDER MAY NOT HANDLE CORRECTLY THIS UNSTANDARD/ILL-FORMED DEPENDENCY" << std::endl;
155
//new_name = filename.substr(0, filename.find(".")) + ".dylib";
159
void Dependency::print()
161
std::cout << std::endl;
162
std::cout << " * " << filename.c_str() << " from " << prefix.c_str() << std::endl;
164
const int symamount = symlinks.size();
165
for(int n=0; n<symamount; n++)
166
std::cout << " symlink --> " << symlinks[n].c_str() << std::endl;;
169
std::string Dependency::getInstallPath()
171
return Settings::destFolder() + new_name;
173
std::string Dependency::getInnerPath()
175
return Settings::inside_lib_path() + new_name;
179
void Dependency::addSymlink(std::string s){ symlinks.push_back(stripPrefix(s)); }
181
// comapres the given Dependency with this one. If both refer to the same file,
182
// it returns true and merges both entries into one.
183
bool Dependency::mergeIfSameAs(Dependency& dep2)
185
if(dep2.getOriginalFileName().compare(filename) == 0)
187
const int samount = dep2.getSymlinkAmount();
188
for(int n=0; n<samount; n++)
189
addSymlink( dep2.getSymlink(n) ); // FIXME - there may be duplicate symlinks
195
void Dependency::copyYourself()
197
copyFile(getOriginalPath(), getInstallPath());
199
// Fix the lib's inner name
200
std::string command = std::string("install_name_tool -id ") + getInnerPath() + " " + getInstallPath();
201
if( systemp( command ) != 0 )
203
std::cerr << "\n\nError : An error occured while trying to change identity of library " << getInstallPath() << std::endl;
208
void Dependency::fixFileThatDependsOnMe(std::string file_to_fix)
211
std::string command = std::string("install_name_tool -change ") +
212
getOriginalPath() + " " + getInnerPath() + " " + file_to_fix;
214
if( systemp( command ) != 0 )
216
std::cerr << "\n\nError : An error occured while trying to fix depencies of " << file_to_fix << std::endl;
221
const int symamount = symlinks.size();
222
for(int n=0; n<symamount; n++)
224
std::string command = std::string("install_name_tool -change ") +
225
prefix+symlinks[n] + " " + getInnerPath() + " " + file_to_fix;
227
if( systemp( command ) != 0 )
229
std::cerr << "\n\nError : An error occured while trying to fix depencies of " << file_to_fix << std::endl;
239
std::string command = std::string("install_name_tool -change ") +
240
filename + " " + getInnerPath() + " " + file_to_fix;
242
if( systemp( command ) != 0 )
244
std::cerr << "\n\nError : An error occured while trying to fix depencies of " << file_to_fix << std::endl;
249
const int symamount = symlinks.size();
250
for(int n=0; n<symamount; n++)
252
std::string command = std::string("install_name_tool -change ") +
253
symlinks[n] + " " + getInnerPath() + " " + file_to_fix;
255
if( systemp( command ) != 0 )
257
std::cerr << "\n\nError : An error occured while trying to fix depencies of " << file_to_fix << std::endl;
261
}// end if(missing_prefixes)