Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/auriamg/macdylibbundler.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarianne Gagnon <auria.mg@gmail.com>2014-05-30 03:48:42 +0400
committerMarianne Gagnon <auria.mg@gmail.com>2014-05-30 03:48:42 +0400
commitf5f45f47d7c6e9d13544612bdecf089f0e187f76 (patch)
tree9785e74c539af8b816ff575cf0ec5da332799355 /src
parent52af408561c30befe49b6ed2a499c7dbe7cddfe9 (diff)
Initial import
Diffstat (limited to 'src')
-rw-r--r--src/Dependency.cpp270
-rw-r--r--src/Dependency.h66
-rw-r--r--src/DylibBundler.cpp202
-rw-r--r--src/DylibBundler.h34
-rw-r--r--src/Settings.cpp94
-rw-r--r--src/Settings.h59
-rw-r--r--src/Utils.cpp178
-rw-r--r--src/Utils.h45
-rw-r--r--src/main.cpp149
9 files changed, 1097 insertions, 0 deletions
diff --git a/src/Dependency.cpp b/src/Dependency.cpp
new file mode 100644
index 0000000..8140c58
--- /dev/null
+++ b/src/Dependency.cpp
@@ -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)
+}
diff --git a/src/Dependency.h b/src/Dependency.h
new file mode 100644
index 0000000..ca4f153
--- /dev/null
+++ b/src/Dependency.h
@@ -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 \ No newline at end of file
diff --git a/src/DylibBundler.cpp b/src/DylibBundler.cpp
new file mode 100644
index 0000000..0fef302
--- /dev/null
+++ b/src/DylibBundler.cpp
@@ -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));
+ }
+}
diff --git a/src/DylibBundler.h b/src/DylibBundler.h
new file mode 100644
index 0000000..e637e96
--- /dev/null
+++ b/src/DylibBundler.h
@@ -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 \ No newline at end of file
diff --git a/src/Settings.cpp b/src/Settings.cpp
new file mode 100644
index 0000000..12cdad3
--- /dev/null
+++ b/src/Settings.cpp
@@ -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;
+}
+
+} \ No newline at end of file
diff --git a/src/Settings.h b/src/Settings.h
new file mode 100644
index 0000000..701b7a2
--- /dev/null
+++ b/src/Settings.h
@@ -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 \ No newline at end of file
diff --git a/src/Utils.cpp b/src/Utils.cpp
new file mode 100644
index 0000000..9bfc2c6
--- /dev/null
+++ b/src/Utils.cpp
@@ -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());
+}
diff --git a/src/Utils.h b/src/Utils.h
new file mode 100644
index 0000000..36ead35
--- /dev/null
+++ b/src/Utils.h
@@ -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 \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..b8dbd46
--- /dev/null
+++ b/src/main.cpp
@@ -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;
+}