Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion src/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ THE SOFTWARE.
*/

#include "Settings.h"
#include "Utils.h"

#include <vector>
#include <iostream>
#include <fstream>

namespace Settings
{
Expand All @@ -32,6 +36,7 @@ bool overwrite_files = false;
bool overwrite_dir = false;
bool create_dir = false;
bool codesign = true;
std::string codesign_identity = "-";

bool canOverwriteFiles(){ return overwrite_files; }
bool canOverwriteDir(){ return overwrite_dir; }
Expand All @@ -43,6 +48,8 @@ void canOverwriteDir(bool permission){ overwrite_dir = permission; }
void canCreateDir(bool permission){ create_dir = permission; }
void canCodesign(bool permission){ codesign = permission; }

std::string signingIdentity(){ return codesign_identity; }
void signingIdentity(const std::string& str) { codesign_identity = str; }

bool bundleLibs_bool = false;
bool bundleLibs(){ return bundleLibs_bool; }
Expand All @@ -63,6 +70,51 @@ void addFileToFix(const std::string& path){ files.push_back(path); }
int fileToFixAmount(){ return files.size(); }
std::string fileToFix(const int n){ return files[n]; }

namespace {

bool isMachOFile(const std::string& path) {
auto file = std::ifstream{path, std::ios::binary};
if (!file) {
return false;
}

// Read the first 4 bytes
char buffer[4];
if (!file.read(buffer, 4)) {
return false;
}

// Check if the magic number of the file looks like Mach-O file...
if (std::memcmp(buffer, "\xcf\xfa\xed\xfe", 4) == 0 || std::memcmp(buffer, "\xce\xfa\xed\xfe", 4) == 0) {
// Now make sure by calling the `file` command...
static const auto prefix = std::string{"Mach-O"};
auto type = system_get_output("file -b \"" + path + "\"");
return type.compare(0, prefix.length(), prefix) == 0;
}

return false;
}

}

void addFolderToFix(const std::string& path)
{
// we use find as a silly way to list all files inside the folder without
// doing the recursion in C++, which without C++17 std::filesystem is a bit
// cumbersome...
auto all_files = std::vector<std::string>{};
tokenize(system_get_output("find \"" + path + "\""), "\n", &all_files);

auto prefix = std::string{"Mach-O"};
for (auto&& file : all_files) {
if (isMachOFile(file)) {
std::cout << " * Found file " << file << std::endl;
files.push_back(std::move(file));
}
}

}

std::string inside_path_str = "@executable_path/../libs/";
std::string inside_lib_path(){ return inside_path_str; }
void inside_lib_path(const std::string& p)
Expand Down Expand Up @@ -104,7 +156,7 @@ bool isPrefixBundled(const std::string& prefix)
if(prefix.find("@executable_path") != std::string::npos) return false;
if(isSystemLibrary(prefix)) return false;
if(isPrefixIgnored(prefix)) return false;

return true;
}

Expand Down
6 changes: 5 additions & 1 deletion src/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ bool isSystemLibrary(const std::string& prefix);
bool isPrefixBundled(const std::string& prefix);
bool isPrefixIgnored(const std::string& prefix);
void ignore_prefix(std::string prefix);

bool canOverwriteFiles();
void canOverwriteFiles(bool permission);

Expand All @@ -47,13 +47,17 @@ void canCreateDir(bool permission);
bool canCodesign();
void canCodesign(bool permission);

std::string signingIdentity();
void signingIdentity(const std::string& str);

bool bundleLibs();
void bundleLibs(bool on);

std::string destFolder();
void destFolder(const std::string& path);

void addFileToFix(const std::string& path);
void addFolderToFix(const std::string& path);
int fileToFixAmount();
std::string fileToFix(const int n);

Expand Down
31 changes: 16 additions & 15 deletions src/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,27 @@ void setInstallPath(string 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);
}

}


Expand Down Expand Up @@ -106,15 +106,15 @@ void copyFile(const string& from, const string& to)
}

string override_permission = string(override ? "-f " : "-n ");

// copy file to local directory
string command = string("cp ") + override_permission + string("\"") + from + string("\" \"") + to + string("\"");
if( from != to && 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 )
Expand All @@ -129,14 +129,14 @@ std::string system_get_output(const 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);
Expand All @@ -154,10 +154,10 @@ std::string system_get_output(const std::string& cmd)
pclose(command_output);
return "";
}

int return_value = pclose(command_output);
if(return_value != 0) return "";

return full_output;
}

Expand Down Expand Up @@ -223,7 +223,8 @@ void adhocCodeSign(const std::string& file)
if( Settings::canCodesign() == false ) return;

// Add ad-hoc signature for ARM (Apple Silicon) binaries
std::string signCommand = std::string("codesign --force --deep --preserve-metadata=entitlements,requirements,flags,runtime --sign - \"") + file + "\"";
std::string signCommand = std::string("codesign --force --deep --preserve-metadata=entitlements,requirements,flags,runtime --sign ")
+ Settings::signingIdentity() + " \"" + file + "\"";
if( systemp( signCommand ) != 0 )
{
// If the codesigning fails, it may be a bug in Apple's codesign utility.
Expand Down
42 changes: 27 additions & 15 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ THE SOFTWARE.
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 = "1.0.5";
Expand All @@ -53,7 +53,7 @@ void showHelp()
{
std::cout << "dylibbundler " << VERSION << std::endl;
std::cout << "dylibbundler is a utility that helps bundle dynamic libraries inside macOS 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;
Expand All @@ -69,8 +69,8 @@ void showHelp()

int main (int argc, char * const argv[])
{
// parse arguments

// parse arguments
for(int i=0; i<argc; i++)
{
if(strcmp(argv[i],"-x")==0 or strcmp(argv[i],"--fix-file")==0)
Expand All @@ -79,10 +79,16 @@ int main (int argc, char * const argv[])
Settings::addFileToFix(argv[i]);
continue;
}
if(strcmp(argv[i],"-xr")==0 or strcmp(argv[i],"--fix-recursive")==0)
{
i++;
Settings::addFolderToFix(argv[i]);
continue;
}
else if(strcmp(argv[i],"-b")==0 or strcmp(argv[i],"--bundle-deps")==0)
{
Settings::bundleLibs(true);
continue;
continue;
}
else if(strcmp(argv[i],"-p")==0 or strcmp(argv[i],"--install-path")==0)
{
Expand All @@ -105,28 +111,34 @@ int main (int argc, char * const argv[])
else if(strcmp(argv[i],"-of")==0 or strcmp(argv[i],"--overwrite-files")==0)
{
Settings::canOverwriteFiles(true);
continue;
continue;
}
else if(strcmp(argv[i],"-od")==0 or strcmp(argv[i],"--overwrite-dir")==0)
{
Settings::canOverwriteDir(true);
Settings::canCreateDir(true);
continue;
continue;
}
else if(strcmp(argv[i],"-cd")==0 or strcmp(argv[i],"--create-dir")==0)
{
Settings::canCreateDir(true);
continue;
continue;
}
else if(strcmp(argv[i],"-ns")==0 or strcmp(argv[i],"--no-codesign")==0)
{
Settings::canCodesign(false);
continue;
}
else if(strcmp(argv[i],"-si")==0 or strcmp(argv[i],"--signing-identity")==0)
{
i++;
Settings::signingIdentity(argv[i]);
continue;
}
else if(strcmp(argv[i],"-h")==0 or strcmp(argv[i],"--help")==0)
{
showHelp();
exit(0);
exit(0);
}
if(strcmp(argv[i],"-s")==0 or strcmp(argv[i],"--search-path")==0)
{
Expand All @@ -143,21 +155,21 @@ int main (int argc, char * const argv[])
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;
}