/* Copyright (c) 2009-2013 Olivier Chafik, All Rights Reserved This file is part of JNAerator (http://jnaerator.googlecode.com/). JNAerator is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. JNAerator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with JNAerator. If not, see <http://www.gnu.org/licenses/>. */ package com.ochafik.lang.jnaerator; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import com.ochafik.admin.visualstudio.Configuration; import com.ochafik.admin.visualstudio.Project; import com.ochafik.admin.visualstudio.Solution; import com.ochafik.admin.visualstudio.VisualStudioUtils; import com.ochafik.lang.jnaerator.parser.Function; import com.ochafik.lang.jnaerator.parser.Modifier; import com.ochafik.lang.jnaerator.parser.ModifierType; import com.ochafik.util.SystemUtils; import com.nativelibs4java.jalico.Adapter; import com.ochafik.util.string.RegexUtils; import com.ochafik.util.string.StringUtils; public class JNAeratorConfigUtils { public static Logger logger = Logger.getLogger(JNAeratorConfigUtils.class.getName()); public static final class MSC_VER { public final int VC4 = 1000, VC5 = 1100, VC6 = 1200, VC70 = 1300, VC71 = 1310; } static String getProp(String name, String defVal, boolean verbose) { String v = System.getenv(name); v = v == null ? System.getProperty(name, defVal) : v; if (verbose) { logger.log(Level.INFO, "[environment] " + name + "=" + v); } return v; } //this.frameworkspath = new ArrayList<String>(Arrays.asList(new String[] {"/System/Library/Frameworks/", "/Library/Frameworks/", "/Local/Library/Frameworks/"})); static List<String> DEFAULT_FRAMEWORKS_PATH = Arrays.asList( "/System/Library/Frameworks/CoreServices.framework/Versions/Current/Frameworks", "/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/Frameworks", "/System/Library/Frameworks", "/Library/Frameworks", "/Local/Library/Frameworks/", System.getProperty("user.home") + "/Library/Frameworks"); static List<String> DEFAULT_INCLUDE_PATH; static { if (SystemUtils.isMacOSX()) { DEFAULT_INCLUDE_PATH = new ArrayList<String>(); for (String s : new String[]{ "/Developer/SDKs/MacOSX10.5.sdk/usr/include", "/Developer/SDKs/MacOSX10.4u.sdk/usr/include" }) { if (new File(s).exists()) { DEFAULT_INCLUDE_PATH.add(s); break; } } DEFAULT_INCLUDE_PATH.add("."); } else if (SystemUtils.isWindows()) { ArrayList<String> list = new ArrayList<String>(VisualStudioUtils.getMicrosoftIncludes()); list.add("."); DEFAULT_INCLUDE_PATH = list; } else { DEFAULT_INCLUDE_PATH = new ArrayList<String>(Arrays.asList(".")); } if (SystemUtils.isUnix()) { DEFAULT_INCLUDE_PATH.add("/usr/include"); DEFAULT_INCLUDE_PATH.add("/usr/local/include"); /* * /usr/include/c++ is likely to contain directories with versions such as 4.0.0, 4.4.0... * We try to take the greatest version (in lexicographic order of matching dir names) and check that it contains "new" and "map" files */ File cppi = new File("/usr/include/c++"); TreeSet<String> versions = new TreeSet<String>(); if (cppi.isDirectory()) { for (File f : cppi.listFiles()) { if (!f.isDirectory()) { continue; } String n = f.getName(); if (!n.matches("[\\d+](\\.[\\d+])*")) { continue; } if (!(new File(f, "new").exists() && new File(f, "map").exists())) { continue; } versions.add(n); } } if (!versions.isEmpty()) { File d = new File(cppi, versions.last()); DEFAULT_INCLUDE_PATH.add(d.toString()); DEFAULT_INCLUDE_PATH.add(new File(d, "tr1").toString()); } } DEFAULT_INCLUDE_PATH = Collections.unmodifiableList(DEFAULT_INCLUDE_PATH); } public static class FileExtensionFilter implements FileFilter { final Collection<String> allowedExtensions; public FileExtensionFilter(Collection<String> allowedExtensions) { this.allowedExtensions = allowedExtensions; } public FileExtensionFilter(String[] split) { this(Arrays.asList(split)); } public boolean accept(File file) { String name = file.getName().toLowerCase(); int i = name.lastIndexOf('.'); return accept(file, i > 0 ? name.substring(i + 1) : ""); } public boolean accept(File file, String extension) { return allowedExtensions.contains(extension); } } public static void addCPlusPlus(JNAeratorConfig.PreprocessorConfig config) { config.implicitMacros.put("__cplusplus", null); } public static void addGCCPredefinedMacros(JNAeratorConfig.PreprocessorConfig config) { //gcc -dM -E - < /dev/null config.implicitMacros.put("__DBL_MIN_EXP__", "(-1021)"); config.implicitMacros.put("__FLT_MIN__", "1.17549435e-38F"); config.implicitMacros.put("__CHAR_BIT__", "8"); config.implicitMacros.put("__WCHAR_MAX__", "2147483647"); config.implicitMacros.put("__DBL_DENORM_MIN__", "4.9406564584124654e-324"); config.implicitMacros.put("__FLT_EVAL_METHOD__", "0"); config.implicitMacros.put("__DBL_MIN_10_EXP__", "(-307)"); config.implicitMacros.put("__FINITE_MATH_ONLY__", "0"); config.implicitMacros.put("__SHRT_MAX__", "32767"); config.implicitMacros.put("__LDBL_MAX__", "1.18973149535723176502e+4932L"); if (com.sun.jna.Platform.isMac()) { config.implicitMacros.put("__APPLE_CC__", "5484"); config.implicitMacros.put("__MACH__", "1"); config.implicitMacros.put("__APPLE__", "1"); } config.implicitMacros.put("__UINTMAX_TYPE__", "long long unsigned int"); config.implicitMacros.put("__SCHAR_MAX__", "127"); config.implicitMacros.put("__USER_LABEL_PREFIX__", "_"); config.implicitMacros.put("__STDC_HOSTED__", "1"); config.implicitMacros.put("__DBL_DIG__", "15"); config.implicitMacros.put("__FLT_EPSILON__", "1.19209290e-7F"); config.implicitMacros.put("__LDBL_MIN__", "3.36210314311209350626e-4932L"); config.implicitMacros.put("__strong", ""); config.implicitMacros.put("__DECIMAL_DIG__", "21"); config.implicitMacros.put("__LDBL_HAS_QUIET_NAN__", "1"); config.implicitMacros.put("__DYNAMIC__", "1"); // config.implicitMacros.put("__GNUC__", "4"); // config.implicitMacros.put("__MMX__", "1"); config.implicitMacros.put("__DBL_MAX__", "1.7976931348623157e+308"); config.implicitMacros.put("__DBL_HAS_INFINITY__", "1"); config.implicitMacros.put("OBJC_NEW_PROPERTIES", "1"); config.implicitMacros.put("__weak", ""); config.implicitMacros.put("__DBL_MAX_EXP__", "1024"); // config.implicitMacros.put("__SSE2_MATH__", "1"); config.implicitMacros.put("__LONG_LONG_MAX__", "9223372036854775807LL"); config.implicitMacros.put("__GXX_ABI_VERSION", "1002"); config.implicitMacros.put("__FLT_MIN_EXP__", "(-125)"); config.implicitMacros.put("__DBL_MIN__", "2.2250738585072014e-308"); config.implicitMacros.put("__DBL_HAS_QUIET_NAN__", "1"); config.implicitMacros.put("__REGISTER_PREFIX__", ""); config.implicitMacros.put("__NO_INLINE__", "1"); // config.implicitMacros.put("__i386", "1"); config.implicitMacros.put("__FLT_MANT_DIG__", "24"); config.implicitMacros.put("__VERSION__", "\"4.0.1 (Apple Inc. build 5484)\""); // config.implicitMacros.put("i386", "1"); // config.implicitMacros.put("__i386__", "1"); config.implicitMacros.put("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", "1055"); config.implicitMacros.put("__SIZE_TYPE__", "long unsigned int"); config.implicitMacros.put("__FLT_RADIX__", "2"); config.implicitMacros.put("__LDBL_EPSILON__", "1.08420217248550443401e-19L"); // config.implicitMacros.put("__SSE_MATH__", "1"); config.implicitMacros.put("__FLT_HAS_QUIET_NAN__", "1"); config.implicitMacros.put("__FLT_MAX_10_EXP__", "38"); config.implicitMacros.put("__LONG_MAX__", "2147483647L"); config.implicitMacros.put("__FLT_HAS_INFINITY__", "1"); config.implicitMacros.put("__LDBL_MANT_DIG__", "64"); config.implicitMacros.put("__CONSTANT_CFSTRINGS__", "1"); config.implicitMacros.put("__WCHAR_TYPE__", "int"); config.implicitMacros.put("__FLT_DIG__", "6"); config.implicitMacros.put("__INT_MAX__", "2147483647"); config.implicitMacros.put("__FLT_MAX_EXP__", "128"); config.implicitMacros.put("__DBL_MANT_DIG__", "53"); config.implicitMacros.put("__WINT_TYPE__", "int"); // config.implicitMacros.put("__SSE__", "1"); config.implicitMacros.put("__LDBL_MIN_EXP__", "(-16381)"); config.implicitMacros.put("__LDBL_MAX_EXP__", "16384"); config.implicitMacros.put("__LDBL_MAX_10_EXP__", "4932"); config.implicitMacros.put("__DBL_EPSILON__", "2.2204460492503131e-16"); config.implicitMacros.put("__LDBL_HAS_INFINITY__", "1"); config.implicitMacros.put("__INTMAX_MAX__", "9223372036854775807LL"); config.implicitMacros.put("__FLT_DENORM_MIN__", "1.40129846e-45F"); config.implicitMacros.put("__PIC__", "1"); config.implicitMacros.put("__FLT_MAX__", "3.40282347e+38F"); // config.implicitMacros.put("__SSE2__", "1"); config.implicitMacros.put("__FLT_MIN_10_EXP__", "(-37)"); config.implicitMacros.put("__INTMAX_TYPE__", "long long int"); config.implicitMacros.put("__GNUC_MINOR__", "0"); config.implicitMacros.put("__DBL_MAX_10_EXP__", "308"); config.implicitMacros.put("__LDBL_DENORM_MIN__", "3.64519953188247460253e-4951L"); // config.implicitMacros.put("__PTRDIFF_TYPE__", "int"); config.implicitMacros.put("__LDBL_MIN_10_EXP__", "(-4931)"); config.implicitMacros.put("__LDBL_DIG__", "18"); // config.implicitMacros.put("__GNUC_GNU_INLINE__", "1"); } static void defaultMacro(JNAeratorConfig config, String name, String value) { if (!config.preprocessorConfig.implicitMacros.containsKey(name)) { config.preprocessorConfig.implicitMacros.put(name, value); } } /** * TODO move this to a .h resource file */ public static void autoConfigure(final JNAeratorConfig config) { if (config.runtime == JNAeratorConfig.Runtime.BridJ) { config.genCPlusPlus = true; } if (!config.noCPlusPlus) { addCPlusPlus(config.preprocessorConfig); } if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { defaultMacro(config, "__BIG_ENDIAN__", "1"); defaultMacro(config, "G_BYTE_ORDER", "4321"); //glibc: #define G_BIG_ENDIAN 4321 } else { defaultMacro(config, "__LITTLE_ENDIAN__", "1"); defaultMacro(config, "G_BYTE_ORDER", "1234"); //glibc: #define G_LITTLE_ENDIAN 1234 } //prevent a jcpp bug to happen when expanding assert(...) : config.preprocessorConfig.implicitMacros.put("NDEBUG", null); config.preprocessorConfig.implicitMacros.put("__STDC__", null); config.preprocessorConfig.implicitMacros.put("HAVE_PROTOTYPES", null); config.preprocessorConfig.implicitMacros.put("STDC_HEADERS", null); config.preprocessorConfig.implicitIncludes.addAll(getDefaultIncludePath(config.verbose));//JNAeratorConfigUtils.DEFAULT_INCLUDE_PATH); config.preprocessorConfig.frameworksPath.addAll(getDefaultFrameworkPath(config.verbose));//JNAeratorConfigUtils.DEFAULT_FRAMEWORKS_PATH); if (SystemUtils.isWindows()) { //http://msdn.microsoft.com/en-us/library/b0084kay(VS.80).aspx //config.preprocessorConfig.includeStrings.add("#define __declspec(x)\n"); //http://support.microsoft.com/kb/65472 config.preprocessorConfig.implicitMacros.put("_CHAR_UNSIGNED", null); config.preprocessorConfig.implicitMacros.put("WIN32_LEAN_AND_MEAN", null); // http://msdn.microsoft.com/en-us/library/dh8che7s(VS.80).aspx config.preprocessorConfig.implicitMacros.put("_WCHAR_T_DEFINED", null); config.preprocessorConfig.implicitMacros.put("_NATIVE_WCHAR_T_DEFINED", null); defaultMacro(config, "_MSC_VER", "1100"); defaultMacro(config, "WINAPI", "__stdcall"); config.functionsAccepter = new Adapter<Function, Boolean>() { public Boolean adapt(Function value) { return true; /* Set<Modifier> mods = value.getModifiers(); return mods.contains(ModifierType.DllExport) || mods.contains(ModifierType.DllImport) || mods.contains(ModifierType.Extern);*/ } }; //config.preprocessorConfig.implicitMacros.put("") //_CPPRTTI //_DLL //_M_IX86 //_MT //_CPPUNWIND } else { config.preprocessorConfig.implicitMacros.put("__GNUC__", null); if (SystemUtils.isMacOSX()) { config.preprocessorConfig.implicitMacros.put("TARGET_API_MAC_OSX", null); config.preprocessorConfig.implicitMacros.put("__APPLE_CPP__", null); config.preprocessorConfig.implicitMacros.put("__APPLE_CC__", null); // config.preprocessorConfig.implicitMacros.put("FUNCTION_PASCAL", "0"); // config.preprocessorConfig.implicitMacros.put("FUNCTION_DECLSPEC", "1"); // config.preprocessorConfig.implicitMacros.put("FUNCTION_WIN32CC", "1"); } config.functionsAccepter = new Adapter<Function, Boolean>() { public Boolean adapt(Function value) { return config.convertBodies || !value.hasModifier(ModifierType.Inline); } }; } config.preprocessorConfig.includeStrings.add(0, "#define __attribute__(x)\n"); JNAeratorConfigUtils.autoConfigureArchitecture(config); } private static Collection<? extends String> getDefaultFrameworkPath(boolean verbose) { return Arrays.asList(getProp("JNAERATOR_FRAMEWORKS_PATH", StringUtils.implode(DEFAULT_FRAMEWORKS_PATH, File.pathSeparator), verbose).split(File.pathSeparator)); } private static Collection<? extends String> getDefaultIncludePath(boolean verbose) { return Arrays.asList(getProp("JNAERATOR_INCLUDE_PATH", StringUtils.implode(DEFAULT_INCLUDE_PATH, File.pathSeparator), verbose).split(File.pathSeparator)); } /** * TODO move this to a .h resource file <ul> <li> endianness <li> * TARGET_CPU_* : see * /System/Library/Frameworks/CoreServices.framework/Versions/Current/Frameworks/CarbonCore.framework/Headers/fp.h * </ul> * * @param config */ static void autoConfigureArchitecture(JNAeratorConfig config) { String arch = System.getProperty("os.arch").toLowerCase(); if (config.verbose) { System.out.println("os.arch = " + arch); } //protect us from inline assembly in VC++: //config.preprocessorConfig.implicitMacros.put("_M_CEE_PURE", null); if (arch.equals("x86_64") || arch.equals("amd64")) { config.preprocessorConfig.implicitMacros.put("TARGET_CPU_X86_64", null); config.preprocessorConfig.implicitMacros.put("__i386__", null); config.preprocessorConfig.implicitMacros.put("__x86_64__", null); config.preprocessorConfig.implicitMacros.put("__amd64__", null); config.preprocessorConfig.implicitMacros.put("__LITTLE_ENDIAN__", null); config.preprocessorConfig.implicitMacros.put("M_I86", "1"); config.preprocessorConfig.implicitMacros.put("_M_I86", "1"); config.preprocessorConfig.implicitMacros.put("_WIN32", "1"); // config.preprocessorConfig.implicitMacros.put("M_X64", "1"); // config.preprocessorConfig.implicitMacros.put("_M_X64", "1"); // config.preprocessorConfig.implicitMacros.put("_WIN64", "1"); } else if (arch.equals("i386") || arch.equals("x86")) { config.preprocessorConfig.implicitMacros.put("TARGET_CPU_X86", null); config.preprocessorConfig.implicitMacros.put("__i386__", null); config.preprocessorConfig.implicitMacros.put("__LITTLE_ENDIAN__", null); config.preprocessorConfig.implicitMacros.put("M_I86", "1"); config.preprocessorConfig.implicitMacros.put("_M_I86", "1"); config.preprocessorConfig.implicitMacros.put("_WIN32", "1"); } else if (arch.equals("ppc")) { config.preprocessorConfig.implicitMacros.put("TARGET_CPU_PPC", null); config.preprocessorConfig.implicitMacros.put("__PPC__", null); config.preprocessorConfig.implicitMacros.put("__powerpc__", null); config.preprocessorConfig.implicitMacros.put("__BIG_ENDIAN__", null); } else if (arch.equals("ppc64")) { config.preprocessorConfig.implicitMacros.put("TARGET_CPU_PPC64", null); config.preprocessorConfig.implicitMacros.put("__PPC_64__", null); // config.preprocessorConfig.implicitMacros.put("__powerpc64__", null); config.preprocessorConfig.implicitMacros.put("__BIG_ENDIAN__", null); } } public static void readProjectConfig(File projectFile, String configName, final JNAeratorConfig config) throws Exception { String projectFileName = projectFile.getName(); config.rootDirectoriesPrefixesForSourceComments.add(projectFile.getCanonicalFile().getParent() + File.separator); if (projectFileName.endsWith(".sln")) { if (configName == null) { configName = "Release|Win32"; } for (String include : VisualStudioUtils.getMicrosoftIncludes()) { include = new File(include).getCanonicalPath(); config.preprocessorConfig.implicitIncludes.add(include); if (!include.endsWith(File.separator)) { include = include + File.separator; } config.rootDirectoriesPrefixesForSourceComments.add(include); } Solution solution = new Solution(projectFile); solution.parseProjects(config.fileFilter); //final Map<String, FileConfiguration> configsByFile = new LinkedHashMap<String, FileConfiguration>(); //final Map<File, String> libraryDLLByFile = new LinkedHashMap<File, String>(); for (Project project : solution.getProjects()) { String projectConfigName = project.activeConfigurationNameBySolutionConfigurationName.get(configName); if (projectConfigName == null) { projectConfigName = configName; } // throw new IOException("Solution configuration with name '" + configName + "' does correspond to any configuration in project '" + project.name + "' (available configs : " + // StringUtils.implode(project.activeConfigurationNameBySolutionConfigurationName.keySet(), ", ") + ")"); Configuration configuration = project.configurations.get(projectConfigName); String libraryFile = configuration.outputFile == null ? project.name : RegexUtils.findFirst(configuration.outputFile, Pattern.compile("^(.*?)(\\.[^.]*)?$"), 1); config.libraryProjectSources.put(libraryFile, project.projectFile.getCanonicalFile()); System.out.println("project " + project.name + ": library = " + libraryFile); if (configuration != null) { System.out.println("preprocessorDefinitions : " + configuration.preprocessorDefinitions); for (String def : configuration.preprocessorDefinitions) { config.preprocessorConfig.implicitMacros.put(def, ""); } } for (File file : project.files) { try { file = file.getCanonicalFile(); System.out.println(file + "\n\t-> " + libraryFile); config.addSourceFile(file, libraryFile, false, true, true); //config.preprocessorConfig //config.libraryByFile.put(file, libraryFile) } catch (IOException ex) { ex.printStackTrace(); } } } if (config.preprocessorConfig.implicitMacros.containsKey("WIN32") || config.preprocessorConfig.implicitMacros.containsKey("_WIN32")) { config.preprocessorConfig.implicitMacros.put("_M_IX86", ""); } else if (config.preprocessorConfig.implicitMacros.containsKey("WIN64") || config.preprocessorConfig.implicitMacros.containsKey("_WIN64")) { config.preprocessorConfig.implicitMacros.put("_M_AMD64", ""); } } } public static File getFrameworkHeaderDirectory(String framework, List<String> frameworksPath) throws IOException { return new File(getFrameworkDirectory(framework, frameworksPath), "Headers"); } public static File getFrameworkDirectory(String framework, List<String> frameworksPath) throws IOException { File file = new File(framework); if (!file.getName().matches("\\.framework$") || !file.exists()) { for (String pathEl : frameworksPath) { File f = new File(pathEl, framework + ".framework"); if (f.exists() && f.isDirectory()) { file = f; break; } } } if (!file.exists()) { throw new IOException("Could not find framework '" + framework + "' in path " + frameworksPath); } return file; } }