Initial import
This commit is contained in:
parent
52af408561
commit
f5f45f47d7
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 auriamg
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
dylibbundler:
|
||||
g++ -c -I./src ./src/Settings.cpp -o ./Settings.o
|
||||
g++ -c -I./src ./src/DylibBundler.cpp -o ./DylibBundler.o
|
||||
g++ -c -I./src ./src/Dependency.cpp -o ./Dependency.o
|
||||
g++ -c -I./src ./src/main.cpp -o ./main.o
|
||||
g++ -c -I./src ./src/Utils.cpp -o ./Utils.o
|
||||
g++ -o ./dylibbundler ./Settings.o ./DylibBundler.o ./Dependency.o ./main.o ./Utils.o
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f ./dylibbundler
|
||||
|
||||
install: dylibbundler
|
||||
cp ./dylibbundler /usr/local/bin/dylibbundler
|
||||
chmod 775 /usr/local/bin/dylibbundler
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Dependency.h"
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <sys/param.h>
|
||||
#include "Utils.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
std::string stripPrefix(std::string in)
|
||||
{
|
||||
return in.substr(in.rfind("/")+1);
|
||||
}
|
||||
|
||||
//the pathes to search for dylibs, store it globally to parse the environment variables only once
|
||||
std::vector<std::string> pathes;
|
||||
|
||||
//initialize the dylib search pathes
|
||||
void initSearchPathes(){
|
||||
//Check the same pathes the system would search for dylibs
|
||||
std::string searchPathes;
|
||||
char *dyldLibPath = std::getenv("DYLD_LIBRARY_PATH");
|
||||
if( dyldLibPath!=0 )
|
||||
searchPathes = dyldLibPath;
|
||||
dyldLibPath = std::getenv("DYLD_FALLBACK_FRAMEWORK_PATH");
|
||||
if (dyldLibPath != 0)
|
||||
{
|
||||
if (!searchPathes.empty() && searchPathes[ searchPathes.size()-1 ] != ':') searchPathes += ":";
|
||||
searchPathes += dyldLibPath;
|
||||
}
|
||||
dyldLibPath = std::getenv("DYLD_FALLBACK_LIBRARY_PATH");
|
||||
if (dyldLibPath!=0 )
|
||||
{
|
||||
if (!searchPathes.empty() && searchPathes[ searchPathes.size()-1 ] != ':') searchPathes += ":";
|
||||
searchPathes += dyldLibPath;
|
||||
}
|
||||
if (!searchPathes.empty())
|
||||
{
|
||||
std::stringstream ss(searchPathes);
|
||||
std::string item;
|
||||
while(std::getline(ss, item, ':'))
|
||||
{
|
||||
if (item[ item.size()-1 ] != '/') item += "/";
|
||||
pathes.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if some libs are missing prefixes, this will be set to true
|
||||
// more stuff will then be necessary to do
|
||||
bool missing_prefixes = false;
|
||||
|
||||
Dependency::Dependency(std::string path)
|
||||
{
|
||||
// check if given path is a symlink
|
||||
std::string cmd = "readlink -n " + path;
|
||||
const bool is_symlink = system( (cmd+" > /dev/null").c_str())==0;
|
||||
if (is_symlink)
|
||||
{
|
||||
char original_file_buffer[PATH_MAX];
|
||||
std::string original_file;
|
||||
|
||||
if (not realpath(path.c_str(), original_file_buffer))
|
||||
{
|
||||
std::cerr << "\n/!\\ WARNING : Cannot resolve symlink '" << path.c_str() << "'" << std::endl;
|
||||
original_file = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
original_file = original_file_buffer;
|
||||
}
|
||||
//original_file = original_file.substr(0, original_file.find("\n") );
|
||||
|
||||
filename = stripPrefix(original_file);
|
||||
prefix = path.substr(0, path.rfind("/")+1);
|
||||
addSymlink(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = stripPrefix(path);
|
||||
prefix = path.substr(0, path.rfind("/")+1);
|
||||
}
|
||||
|
||||
//check if the lib is in a known location
|
||||
if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/";
|
||||
if( prefix.empty() || !fileExists( prefix+filename ) )
|
||||
{
|
||||
//the pathes contains at least /usr/lib so if it is empty we have not initilazed it
|
||||
if( pathes.empty() ) initSearchPathes();
|
||||
|
||||
//check if file is contained in one of the pathes
|
||||
for( size_t i=0; i<pathes.size(); ++i)
|
||||
{
|
||||
if (fileExists( pathes[i]+filename ))
|
||||
{
|
||||
std::cout << "FOUND " << filename << " in " << pathes[i] << std::endl;
|
||||
prefix = pathes[i];
|
||||
missing_prefixes = true; //the prefix was missing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If the location is still unknown, ask the user for search path
|
||||
if( prefix.empty() || !fileExists( prefix+filename ) )
|
||||
{
|
||||
std::cerr << "\n/!\\ WARNING : Library " << filename << " has an incomplete name (location unknown)" << std::endl;
|
||||
missing_prefixes = true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::cout << "Please specify now where this library can be found (or write 'quit' to abort): "; fflush(stdout);
|
||||
|
||||
char buffer[128];
|
||||
std::cin >> buffer;
|
||||
prefix = buffer;
|
||||
std::cout << std::endl;
|
||||
|
||||
if(prefix.compare("quit")==0) exit(1);
|
||||
|
||||
if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/";
|
||||
|
||||
if( !fileExists( prefix+filename ) )
|
||||
{
|
||||
std::cerr << (prefix+filename) << " does not exist. Try again" << std::endl;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
pathes.push_back( prefix );
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//new_name = filename.substr(0, filename.find(".")) + ".dylib";
|
||||
new_name = filename;
|
||||
}
|
||||
|
||||
void Dependency::print()
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << " * " << filename.c_str() << " from " << prefix.c_str() << std::endl;
|
||||
|
||||
const int symamount = symlinks.size();
|
||||
for(int n=0; n<symamount; n++)
|
||||
std::cout << " symlink --> " << symlinks[n].c_str() << std::endl;;
|
||||
}
|
||||
|
||||
std::string Dependency::getInstallPath()
|
||||
{
|
||||
return Settings::destFolder() + new_name;
|
||||
}
|
||||
std::string Dependency::getInnerPath()
|
||||
{
|
||||
return Settings::inside_lib_path() + new_name;
|
||||
}
|
||||
|
||||
|
||||
void Dependency::addSymlink(std::string s){ symlinks.push_back(stripPrefix(s)); }
|
||||
|
||||
// comapres the given Dependency with this one. If both refer to the same file,
|
||||
// it returns true and merges both entries into one.
|
||||
bool Dependency::mergeIfSameAs(Dependency& dep2)
|
||||
{
|
||||
if(dep2.getOriginalFileName().compare(filename) == 0)
|
||||
{
|
||||
const int samount = dep2.getSymlinkAmount();
|
||||
for(int n=0; n<samount; n++)
|
||||
addSymlink( dep2.getSymlink(n) ); // FIXME - there may be duplicate symlinks
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Dependency::copyYourself()
|
||||
{
|
||||
copyFile(getOriginalPath(), getInstallPath());
|
||||
|
||||
// Fix the lib's inner name
|
||||
std::string command = std::string("install_name_tool -id ") + getInnerPath() + " " + getInstallPath();
|
||||
if( systemp( command ) != 0 )
|
||||
{
|
||||
std::cerr << "\n\nError : An error occured while trying to change identity of library " << getInstallPath() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Dependency::fixFileThatDependsOnMe(std::string file_to_fix)
|
||||
{
|
||||
// for main lib file
|
||||
std::string command = std::string("install_name_tool -change ") +
|
||||
getOriginalPath() + " " + getInnerPath() + " " + file_to_fix;
|
||||
|
||||
if( systemp( command ) != 0 )
|
||||
{
|
||||
std::cerr << "\n\nError : An error occured while trying to fix depencies of " << file_to_fix << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// for symlinks
|
||||
const int symamount = symlinks.size();
|
||||
for(int n=0; n<symamount; n++)
|
||||
{
|
||||
std::string command = std::string("install_name_tool -change ") +
|
||||
prefix+symlinks[n] + " " + getInnerPath() + " " + file_to_fix;
|
||||
|
||||
if( systemp( command ) != 0 )
|
||||
{
|
||||
std::cerr << "\n\nError : An error occured while trying to fix depencies of " << file_to_fix << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME - hackish
|
||||
if(missing_prefixes)
|
||||
{
|
||||
// for main lib file
|
||||
std::string command = std::string("install_name_tool -change ") +
|
||||
filename + " " + getInnerPath() + " " + file_to_fix;
|
||||
|
||||
if( systemp( command ) != 0 )
|
||||
{
|
||||
std::cerr << "\n\nError : An error occured while trying to fix depencies of " << file_to_fix << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// for symlinks
|
||||
const int symamount = symlinks.size();
|
||||
for(int n=0; n<symamount; n++)
|
||||
{
|
||||
std::string command = std::string("install_name_tool -change ") +
|
||||
symlinks[n] + " " + getInnerPath() + " " + file_to_fix;
|
||||
|
||||
if( systemp( command ) != 0 )
|
||||
{
|
||||
std::cerr << "\n\nError : An error occured while trying to fix depencies of " << file_to_fix << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}//next
|
||||
}// end if(missing_prefixes)
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _depend_h_
|
||||
#define _depend_h_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Dependency
|
||||
{
|
||||
// origin
|
||||
std::string filename;
|
||||
std::string prefix;
|
||||
std::vector<std::string> symlinks;
|
||||
|
||||
// installation
|
||||
std::string new_name;
|
||||
public:
|
||||
Dependency(std::string path);
|
||||
|
||||
void print();
|
||||
|
||||
std::string getOriginalFileName() const{ return filename; }
|
||||
std::string getOriginalPath() const{ return prefix+filename; }
|
||||
std::string getInstallPath();
|
||||
std::string getInnerPath();
|
||||
|
||||
void addSymlink(std::string s);
|
||||
int getSymlinkAmount() const{ return symlinks.size(); }
|
||||
|
||||
std::string getSymlink(const int i) const{ return symlinks[i]; }
|
||||
std::string getPrefix() const{ return prefix; }
|
||||
|
||||
void copyYourself();
|
||||
void fixFileThatDependsOnMe(std::string file);
|
||||
|
||||
// comapres the given Dependency with this one. If both refer to the same file,
|
||||
// it returns true and merges both entries into one.
|
||||
bool mergeIfSameAs(Dependency& dep2);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "DylibBundler.h"
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include "Utils.h"
|
||||
#include "Settings.h"
|
||||
#include "Dependency.h"
|
||||
|
||||
|
||||
std::vector<Dependency> deps;
|
||||
|
||||
void changeLibPathsOnFile(std::string file_to_fix)
|
||||
{
|
||||
std::cout << "\n* Fixing dependencies on " << file_to_fix.c_str() << std::endl;
|
||||
|
||||
const int dep_amount = deps.size();
|
||||
for(int n=0; n<dep_amount; n++)
|
||||
{
|
||||
deps[n].fixFileThatDependsOnMe(file_to_fix);
|
||||
}
|
||||
}
|
||||
|
||||
void addDependency(std::string path)
|
||||
{
|
||||
Dependency dep(path);
|
||||
|
||||
// we need to check if this library was already added to avoid duplicates
|
||||
const int dep_amount = deps.size();
|
||||
for(int n=0; n<dep_amount; n++)
|
||||
{
|
||||
if(dep.mergeIfSameAs(deps[n])) return;
|
||||
}
|
||||
|
||||
if(!Settings::isPrefixBundled(dep.getPrefix())) return;
|
||||
|
||||
deps.push_back(dep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill vector 'lines' with dependencies of given 'filename'
|
||||
*/
|
||||
void collectDependencies(std::string filename, std::vector<std::string>& lines)
|
||||
{
|
||||
// execute "otool -L" on the given file and collect the command's output
|
||||
std::string cmd = "otool -L " + filename;
|
||||
std::string output = system_get_output(cmd);
|
||||
|
||||
if(output.find("can't open file")!=std::string::npos or output.find("No such file")!=std::string::npos or output.size()<1)
|
||||
{
|
||||
std::cerr << "Cannot find file " << filename << " to read its dependencies" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// split output
|
||||
tokenize(output, "\n", &lines);
|
||||
}
|
||||
|
||||
|
||||
void collectDependencies(std::string filename)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
collectDependencies(filename, lines);
|
||||
|
||||
std::cout << "."; fflush(stdout);
|
||||
|
||||
const int line_amount = lines.size();
|
||||
for(int n=0; n<line_amount; n++)
|
||||
{
|
||||
std::cout << "."; fflush(stdout);
|
||||
if(lines[n][0] != '\t') continue; // only lines beginning with a tab interest us
|
||||
if( lines[n].find(".framework") != std::string::npos ) continue; //Ignore frameworks, we can not handle them
|
||||
|
||||
addDependency( // trim useless info, keep only library name
|
||||
lines[n].substr(1, lines[n].find(" (") )
|
||||
);
|
||||
}
|
||||
}
|
||||
void collectSubDependencies()
|
||||
{
|
||||
// print status to user
|
||||
int dep_amount = deps.size();
|
||||
|
||||
// recursively collect each dependencie's dependencies
|
||||
while(true)
|
||||
{
|
||||
dep_amount = deps.size();
|
||||
for(int n=0; n<dep_amount; n++)
|
||||
{
|
||||
std::cout << "."; fflush(stdout);
|
||||
std::vector<std::string> lines;
|
||||
collectDependencies(deps[n].getOriginalPath(), lines);
|
||||
|
||||
const int line_amount = lines.size();
|
||||
for(int n=0; n<line_amount; n++)
|
||||
{
|
||||
if(lines[n][0] != '\t') continue; // only lines beginning with a tab interest us
|
||||
if( lines[n].find(".framework") != std::string::npos ) continue; //Ignore frameworks, we can not handle them
|
||||
|
||||
addDependency( // trim useless info, keep only library name
|
||||
lines[n].substr(1, lines[n].find(" (") )
|
||||
);
|
||||
}//next
|
||||
}//next
|
||||
|
||||
if(deps.size() == dep_amount) break; // no more dependencies were added on this iteration, stop searching
|
||||
}
|
||||
}
|
||||
|
||||
void createDestDir()
|
||||
{
|
||||
std::string dest_folder = Settings::destFolder();
|
||||
std::cout << "* Checking output directory " << dest_folder.c_str() << std::endl;
|
||||
|
||||
// ----------- check dest folder stuff ----------
|
||||
bool dest_exists = fileExists(dest_folder);
|
||||
|
||||
if(dest_exists and Settings::canOverwriteDir())
|
||||
{
|
||||
std::cout << "* Erasing old output directory " << dest_folder.c_str() << std::endl;
|
||||
std::string command = std::string("rm -r ") + dest_folder;
|
||||
if( systemp( command ) != 0)
|
||||
{
|
||||
std::cerr << "\n\nError : An error occured while attempting to override dest folder." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
dest_exists = false;
|
||||
}
|
||||
|
||||
if(!dest_exists)
|
||||
{
|
||||
|
||||
if(Settings::canCreateDir())
|
||||
{
|
||||
std::cout << "* Creating output directory " << dest_folder.c_str() << std::endl;
|
||||
std::string command = std::string("mkdir -p ") + dest_folder;
|
||||
if( systemp( command ) != 0)
|
||||
{
|
||||
std::cerr << "\n\nError : An error occured while creating dest folder." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "\n\nError : Dest folder does not exist. Create it or pass the appropriate flag for automatic dest dir creation." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void doneWithDeps_go()
|
||||
{
|
||||
std::cout << std::endl;
|
||||
const int dep_amount = deps.size();
|
||||
// print info to user
|
||||
for(int n=0; n<dep_amount; n++)
|
||||
{
|
||||
deps[n].print();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// copy files if requested by user
|
||||
if(Settings::bundleLibs())
|
||||
{
|
||||
createDestDir();
|
||||
|
||||
for(int n=0; n<dep_amount; n++)
|
||||
{
|
||||
deps[n].copyYourself();
|
||||
changeLibPathsOnFile(deps[n].getInstallPath());
|
||||
}
|
||||
}
|
||||
|
||||
const int fileToFixAmount = Settings::fileToFixAmount();
|
||||
for(int n=0; n<fileToFixAmount; n++)
|
||||
{
|
||||
changeLibPathsOnFile(Settings::fileToFix(n));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _crawler_
|
||||
#define _crawler_
|
||||
|
||||
#include <string>
|
||||
|
||||
void collectDependencies(std::string filename);
|
||||
void collectSubDependencies();
|
||||
void doneWithDeps_go();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Settings.h"
|
||||
#include <vector>
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
|
||||
bool overwrite_files = false;
|
||||
bool overwrite_dir = false;
|
||||
bool create_dir = false;
|
||||
|
||||
bool canOverwriteFiles(){ return overwrite_files; }
|
||||
bool canOverwriteDir(){ return overwrite_dir; }
|
||||
bool canCreateDir(){ return create_dir; }
|
||||
|
||||
void canOverwriteFiles(bool permission){ overwrite_files = permission; }
|
||||
void canOverwriteDir(bool permission){ overwrite_dir = permission; }
|
||||
void canCreateDir(bool permission){ create_dir = permission; }
|
||||
|
||||
|
||||
bool bundleLibs_bool = false;
|
||||
bool bundleLibs(){ return bundleLibs_bool; }
|
||||
void bundleLibs(bool on){ bundleLibs_bool = on; }
|
||||
|
||||
|
||||
std::string dest_folder_str = "./libs/";
|
||||
std::string destFolder(){ return dest_folder_str; }
|
||||
void destFolder(std::string path)
|
||||
{
|
||||
dest_folder_str = path;
|
||||
// fix path if needed so it ends with '/'
|
||||
if( dest_folder_str[ dest_folder_str.size()-1 ] != '/' ) dest_folder_str += "/";
|
||||
}
|
||||
|
||||
std::vector<std::string> files;
|
||||
void addFileToFix(std::string path){ files.push_back(path); }
|
||||
int fileToFixAmount(){ return files.size(); }
|
||||
std::string fileToFix(const int n){ return files[n]; }
|
||||
|
||||
std::string inside_path_str = "@executable_path/../libs/";
|
||||
std::string inside_lib_path(){ return inside_path_str; }
|
||||
void inside_lib_path(std::string p)
|
||||
{
|
||||
inside_path_str = p;
|
||||
// fix path if needed so it ends with '/'
|
||||
if( inside_path_str[ inside_path_str.size()-1 ] != '/' ) inside_path_str += "/";
|
||||
}
|
||||
|
||||
std::vector<std::string> prefixes_to_ignore;
|
||||
void ignore_prefix(std::string prefix)
|
||||
{
|
||||
if( prefix[ prefix.size()-1 ] != '/' ) prefix += "/";
|
||||
prefixes_to_ignore.push_back(prefix);
|
||||
}
|
||||
|
||||
bool isPrefixBundled(std::string prefix)
|
||||
{
|
||||
if(prefix.find(".framework") != std::string::npos) return false;
|
||||
if(prefix.find("@executable_path") != std::string::npos) return false;
|
||||
if(prefix.compare("/usr/lib/") == 0) return false;
|
||||
|
||||
const int prefix_amount = prefixes_to_ignore.size();
|
||||
for(int n=0; n<prefix_amount; n++)
|
||||
{
|
||||
if(prefix.compare(prefixes_to_ignore[n]) == 0) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _settings_
|
||||
#define _settings_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
|
||||
bool isPrefixBundled(std::string prefix);
|
||||
void ignore_prefix(std::string prefix);
|
||||
|
||||
bool canOverwriteFiles();
|
||||
void canOverwriteFiles(bool permission);
|
||||
|
||||
bool canOverwriteDir();
|
||||
void canOverwriteDir(bool permission);
|
||||
|
||||
bool canCreateDir();
|
||||
void canCreateDir(bool permission);
|
||||
|
||||
bool bundleLibs();
|
||||
void bundleLibs(bool on);
|
||||
|
||||
std::string destFolder();
|
||||
void destFolder(std::string path);
|
||||
|
||||
void addFileToFix(std::string path);
|
||||
int fileToFixAmount();
|
||||
std::string fileToFix(const int n);
|
||||
|
||||
std::string inside_lib_path();
|
||||
void inside_lib_path(std::string p);
|
||||
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Dependency.h"
|
||||
#include "Settings.h"
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
void setInstallPath(string loc)
|
||||
{
|
||||
path_to_libs_folder = loc;
|
||||
}*/
|
||||
|
||||
void tokenize(const string& str, const char* delim, vector<string>* vectorarg)
|
||||
{
|
||||
vector<string>& tokens = *vectorarg;
|
||||
|
||||
string delimiters(delim);
|
||||
|
||||
// skip delimiters at beginning.
|
||||
string::size_type lastPos = str.find_first_not_of( delimiters , 0);
|
||||
|
||||
// find first "non-delimiter".
|
||||
string::size_type pos = str.find_first_of(delimiters, lastPos);
|
||||
|
||||
while (string::npos != pos || string::npos != lastPos)
|
||||
{
|
||||
// found a token, add it to the vector.
|
||||
tokens.push_back(str.substr(lastPos, pos - lastPos));
|
||||
|
||||
// skip delimiters. Note the "not_of"
|
||||
lastPos = str.find_first_not_of(delimiters, pos);
|
||||
|
||||
// find next "non-delimiter"
|
||||
pos = str.find_first_of(delimiters, lastPos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool fileExists( std::string filename )
|
||||
{
|
||||
if (access( filename.c_str(), F_OK ) != -1)
|
||||
{
|
||||
return true; // file exists
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "access(filename) returned -1 on filename [" << filename << "] I will try trimming." << std::endl;
|
||||
std::string delims = " \f\n\r\t\v";
|
||||
std::string rtrimmed = filename.substr(0, filename.find_last_not_of(delims) + 1);
|
||||
std::string ftrimmed = rtrimmed.substr(rtrimmed.find_first_not_of(delims));
|
||||
if (access( ftrimmed.c_str(), F_OK ) != -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "Still failed. Cannot find the specified file." << std::endl;
|
||||
return false;// file doesn't exist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fixLibDependency(string old_lib_path, string new_lib_name, string target_file_name)
|
||||
{
|
||||
|
||||
string command = string("install_name_tool -change ") + old_lib_path + string(" ") + Settings::inside_lib_path() + new_lib_name + string(" ") + target_file_name;
|
||||
if( systemp( command ) != 0 )
|
||||
{
|
||||
cerr << "\n\nError : An error occured while trying to fix depency of " << old_lib_path << " in " << target_file_name << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void copyFile(string from, string to)
|
||||
{
|
||||
bool override = Settings::canOverwriteFiles();
|
||||
if(!override)
|
||||
{
|
||||
if(fileExists( to ))
|
||||
{
|
||||
cerr << "\n\nError : File " << to.c_str() << " already exists. Remove it or enable overriding." << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
string override_permission = string(override ? "-f " : "-n ");
|
||||
|
||||
// copy file to local directory
|
||||
string command = string("cp ") + override_permission + from + string(" ") + to;
|
||||
if( systemp( command ) != 0 )
|
||||
{
|
||||
cerr << "\n\nError : An error occured while trying to copy file " << from << " to " << to << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// give it write permission
|
||||
string command2 = string("chmod +w ") + to;
|
||||
if( systemp( command2 ) != 0 )
|
||||
{
|
||||
cerr << "\n\nError : An error occured while trying to set write permissions on file " << to << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string system_get_output(std::string cmd)
|
||||
{
|
||||
FILE * command_output;
|
||||
char output[128];
|
||||
int amount_read = 1;
|
||||
|
||||
std::string full_output;
|
||||
|
||||
try
|
||||
{
|
||||
command_output = popen(cmd.c_str(), "r");
|
||||
if(command_output == NULL) throw;
|
||||
|
||||
while(amount_read > 0)
|
||||
{
|
||||
amount_read = fread(output, 1, 127, command_output);
|
||||
if(amount_read <= 0) break;
|
||||
else
|
||||
{
|
||||
output[amount_read] = '\0';
|
||||
full_output += output;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cerr << "An error occured while executing command " << cmd.c_str() << std::endl;
|
||||
pclose(command_output);
|
||||
return "";
|
||||
}
|
||||
|
||||
int return_value = pclose(command_output);
|
||||
if(return_value != 0) return "";
|
||||
|
||||
return full_output;
|
||||
}
|
||||
|
||||
int systemp(std::string& cmd)
|
||||
{
|
||||
std::cout << " " << cmd.c_str() << std::endl;
|
||||
return system(cmd.c_str());
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _utils_h_
|
||||
#define _utils_h_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Library;
|
||||
|
||||
void tokenize(const std::string& str, const char* delimiters, std::vector<std::string>*);
|
||||
bool fileExists( std::string filename );
|
||||
|
||||
void copyFile(std::string from, std::string to);
|
||||
|
||||
// executes a command in the native shell and returns output in string
|
||||
std::string system_get_output(std::string cmd);
|
||||
|
||||
// like 'system', runs a command on the system shell, but also prints the command to stdout.
|
||||
int systemp(std::string& cmd);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marianne Gagnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "Settings.h"
|
||||
|
||||
#include "Utils.h"
|
||||
#include "DylibBundler.h"
|
||||
|
||||
/*
|
||||
TODO
|
||||
- what happens if a library is not remembered by full path but only name? (support improved, still not perfect)
|
||||
- could get mixed up if symlink and original are not in the same location (won't happen for UNIX prefixes like /usr/, but in random directories?)
|
||||
|
||||
FIXME: why does it copy plugins i try to fix to the libs directory?
|
||||
|
||||
*/
|
||||
|
||||
const std::string VERSION = "0.4.1";
|
||||
|
||||
|
||||
// FIXME - no memory management is done at all (anyway the program closes immediately so who cares?)
|
||||
|
||||
std::string installPath = "";
|
||||
|
||||
|
||||
void showHelp()
|
||||
{
|
||||
std::cout << "dylibbundler " << VERSION << std::endl;
|
||||
std::cout << "dylibbundler is a utility that helps bundle dynamic libraries inside mac OS X app bundles.\n" << std::endl;
|
||||
|
||||
std::cout << "-x, --fix-file <file to fix (executable or app plug-in)>" << std::endl;
|
||||
std::cout << "-b, --bundle-deps" << std::endl;
|
||||
std::cout << "-d, --dest-dir <directory to send bundled libraries (relative to cwd)>" << std::endl;
|
||||
std::cout << "-p, --install-path <'inner' path of bundled libraries (usually relative to executable, by default '@executable_path/../libs/')>" << std::endl;
|
||||
std::cout << "-of, --overwrite-files (allow overwriting files in output directory)" << std::endl;
|
||||
std::cout << "-od, --overwrite-dir (totally overwrite output directory if it already exists. implies --create-dir)" << std::endl;
|
||||
std::cout << "-cd, --create-dir (creates output directory if necessary)" << std::endl;
|
||||
std::cout << "-i, --ignore <location to ignore> (will ignore libraries in this directory)" << std::endl;
|
||||
std::cout << "-h, --help" << std::endl;
|
||||
}
|
||||
|
||||
int main (int argc, char * const argv[])
|
||||
{
|
||||
|
||||
// parse arguments
|
||||
for(int i=0; i<argc; i++)
|
||||
{
|
||||
if(strcmp(argv[i],"-x")==0 or strcmp(argv[i],"--fix-file")==0)
|
||||
{
|
||||
i++;
|
||||
Settings::addFileToFix(argv[i]);
|
||||
continue;
|
||||
}
|
||||
else if(strcmp(argv[i],"-b")==0 or strcmp(argv[i],"--bundle-deps")==0)
|
||||
{
|
||||
Settings::bundleLibs(true);
|
||||
continue;
|
||||
}
|
||||
else if(strcmp(argv[i],"-p")==0 or strcmp(argv[i],"--install-path")==0)
|
||||
{
|
||||
i++;
|
||||
Settings::inside_lib_path(argv[i]);
|
||||
continue;
|
||||
}
|
||||
else if(strcmp(argv[i],"-i")==0 or strcmp(argv[i],"--ignore")==0)
|
||||
{
|
||||
i++;
|
||||
Settings::ignore_prefix(argv[i]);
|
||||
continue;
|
||||
}
|
||||
else if(strcmp(argv[i],"-d")==0 or strcmp(argv[i],"--dest-dir")==0)
|
||||
{
|
||||
i++;
|
||||
Settings::destFolder(argv[i]);
|
||||
continue;
|
||||
}
|
||||
else if(strcmp(argv[i],"-of")==0 or strcmp(argv[i],"--overwrite-files")==0)
|
||||
{
|
||||
Settings::canOverwriteFiles(true);
|
||||
continue;
|
||||
}
|
||||
else if(strcmp(argv[i],"-od")==0 or strcmp(argv[i],"--overwrite-dir")==0)
|
||||
{
|
||||
Settings::canOverwriteDir(true);
|
||||
Settings::canCreateDir(true);
|
||||
continue;
|
||||
}
|
||||
else if(strcmp(argv[i],"-cd")==0 or strcmp(argv[i],"--create-dir")==0)
|
||||
{
|
||||
Settings::canCreateDir(true);
|
||||
continue;
|
||||
}
|
||||
else if(strcmp(argv[i],"-h")==0 or strcmp(argv[i],"--help")==0)
|
||||
{
|
||||
showHelp();
|
||||
exit(0);
|
||||
}
|
||||
else if(i>0)
|
||||
{
|
||||
// if we meet an unknown flag, abort
|
||||
// ignore first one cause it's usually the path to the executable
|
||||
std::cerr << "Unknown flag " << argv[i] << std::endl << std::endl;
|
||||
showHelp();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(not Settings::bundleLibs() and Settings::fileToFixAmount()<1)
|
||||
{
|
||||
showHelp();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
std::cout << "* Collecting dependencies"; fflush(stdout);
|
||||
|
||||
const int amount = Settings::fileToFixAmount();
|
||||
for(int n=0; n<amount; n++)
|
||||
collectDependencies(Settings::fileToFix(n));
|
||||
|
||||
collectSubDependencies();
|
||||
doneWithDeps_go();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue