1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 #pragma once
27 
28 #include "jucer_LiveCodeBuilderDLL.h"
29 
30 //==============================================================================
31 struct CompileEngineDLL  : private DeletedAtShutdown
32 {
CompileEngineDLLCompileEngineDLL33     CompileEngineDLL()
34     {
35         tryLoadDll();
36     }
37 
~CompileEngineDLLCompileEngineDLL38     ~CompileEngineDLL()
39     {
40         shutdown();
41         clearSingletonInstance();
42     }
43 
tryLoadDllCompileEngineDLL44     bool tryLoadDll()
45     {
46         // never load the dynamic lib multiple times
47         if (! isLoaded())
48         {
49             auto f = findDLLFile();
50 
51             if (f != File() && dll.open (f.getLinkedTarget().getFullPathName()))
52             {
53                #define INIT_LIVE_DLL_FN(name, returnType, params)    name = (name##_type) dll.getFunction (#name);
54                 LIVE_DLL_FUNCTIONS (INIT_LIVE_DLL_FN);
55                #undef INIT_LIVE_DLL_FN
56 
57                 return true;
58             }
59 
60             return false;
61         }
62 
63         return true;
64     }
65 
initialiseCompileEngineDLL66     void initialise (CrashCallbackFunction crashFn, QuitCallbackFunction quitFn, bool setupSignals)
67     {
68         if (isLoaded())
69             projucer_initialise (crashFn, quitFn, setPropertyCallback, getPropertyCallback, setupSignals);
70     }
71 
shutdownCompileEngineDLL72     void shutdown()
73     {
74         if (isLoaded())
75             projucer_shutdown();
76     }
77 
isLoadedCompileEngineDLL78     bool isLoaded() const
79     {
80         #define CHECK_LIVE_DLL_FN(name, returnType, params)    if (name == nullptr) return false;
81         LIVE_DLL_FUNCTIONS (CHECK_LIVE_DLL_FN);
82         #undef CHECK_LIVE_DLL_FN
83 
84         return projucer_getVersion() == requiredVersion;
85     }
86 
87     #define DECLARE_LIVE_DLL_FN(name, returnType, params) \
88         typedef returnType (*name##_type) params; \
89         name##_type name = nullptr;
90 
LIVE_DLL_FUNCTIONSCompileEngineDLL91     LIVE_DLL_FUNCTIONS (DECLARE_LIVE_DLL_FN)
92 
93     #undef DECLARE_LIVE_DLL_FN
94 
95     static String getDLLName()
96     {
97        #if JUCE_MAC
98         return "JUCECompileEngine.dylib";
99        #elif JUCE_LINUX || JUCE_BSD
100         return "JUCECompileEngine.so";
101        #elif JUCE_WINDOWS
102         return "JUCECompileEngine.dll";
103        #else
104         #error
105         return "JUCECompileEngine.so";
106        #endif
107     }
108 
getVersionedUserAppSupportFolderCompileEngineDLL109     static File getVersionedUserAppSupportFolder()
110     {
111         auto userAppData = File::getSpecialLocation (File::userApplicationDataDirectory);
112 
113        #if JUCE_MAC
114         userAppData = userAppData.getChildFile ("Application Support");
115        #endif
116 
117         return userAppData.getChildFile ("Projucer").getChildFile (String ("CompileEngine-") + ProjectInfo::versionString);
118     }
119 
120     JUCE_DECLARE_SINGLETON (CompileEngineDLL, false)
121 
122 private:
123     DynamicLibrary dll;
124 
125     enum { requiredVersion = 2 };
126 
findDLLFileCompileEngineDLL127     static File findDLLFile()
128     {
129         auto dllFile = File();
130 
131         if (tryFindDLLFileInAppFolder (dllFile))
132             return dllFile;
133 
134        #if JUCE_MAC
135         if (tryFindDLLFileInAppBundle(dllFile))
136             return dllFile;
137        #endif
138 
139         if (tryFindDLLFileInAppConfigFolder (dllFile))
140             return dllFile;
141 
142         return {};
143     }
144 
145    #if JUCE_MAC
tryFindDLLFileInAppBundleCompileEngineDLL146     static bool tryFindDLLFileInAppBundle (File& outFile)
147     {
148         File currentAppFile (File::getSpecialLocation (File::currentApplicationFile));
149         return tryFindDLLFileInFolder (currentAppFile.getChildFile ("Contents"), outFile);
150     }
151    #endif
152 
tryFindDLLFileInAppFolderCompileEngineDLL153     static bool tryFindDLLFileInAppFolder (File& outFile)
154     {
155         auto currentAppFile = File::getSpecialLocation (File::currentApplicationFile);
156         return tryFindDLLFileInFolder (currentAppFile.getParentDirectory(), outFile);
157     }
158 
tryFindDLLFileInAppConfigFolderCompileEngineDLL159     static bool tryFindDLLFileInAppConfigFolder (File& outFile)
160     {
161         auto userAppDataFolder = getVersionedUserAppSupportFolder();
162         return tryFindDLLFileInFolder (userAppDataFolder, outFile);
163     }
164 
tryFindDLLFileInFolderCompileEngineDLL165     static bool tryFindDLLFileInFolder(File folder, File& outFile)
166     {
167         auto file = folder.getChildFile (getDLLName());
168         if (isDLLFile (file))
169         {
170             outFile = file;
171             return true;
172         }
173 
174         return false;
175     }
176 
isDLLFileCompileEngineDLL177     static bool isDLLFile (const File& f)
178     {
179         return f.getFileName().equalsIgnoreCase (getDLLName()) && f.exists();
180     }
181 
setPropertyCallbackCompileEngineDLL182     static void setPropertyCallback (const char* key, const char* value)
183     {
184         auto keyStr = String (key);
185         if (keyStr.isNotEmpty())
186             getGlobalProperties().setValue (key, value);
187         else
188             jassertfalse;
189     }
190 
getPropertyCallbackCompileEngineDLL191     static void getPropertyCallback (const char* key, char* value, size_t size)
192     {
193         jassert (getGlobalProperties().getValue (key).getNumBytesAsUTF8() < size);
194 
195         value[0] = 0;
196         getGlobalProperties().getValue (key).copyToUTF8 (value, size);
197     }
198 
crashCallbackCompileEngineDLL199     static void crashCallback (const char*) {}
quitCallbackCompileEngineDLL200     static void quitCallback() {}
201 };
202