import sqlite3.h error: include of non-modular header inside framework module

I am creating a custom back-end framework for my app which encapsulates all my database related logic, so, when we are going to use any database operation, we just need to call that framework function.

Now, for database operations I need to #import <sqlite3.h> in the file called Data.swift where my all database functions exist. But this is swift file so how can I import sqlite..?

  • Can I embed a custom font in a bundle and access it from an ios framework?
  • Can't link MacOS frameworks with CMake
  • FBSDKCoreKit/FBSDKCoreKit.h not found error
  • “Core Data is not a relational database.” Why exactly is this important to know?
  • How to build Cocoa Touch Framework for i386 and x86_64 architecture?
  • Collect Photos of iPhone Library taken between two precise dates
  • When I use bridging-header.h, I receive error

    error: using bridging headers with framework targetsĀ is unsupported
    

    bridging-header.h has #import <sqlite3.h> inside it and set settings Bridging Header variable.

    If I add import statement in Umbrella header which gives me the error

    include of non-modular header inside framework module
    

    I googled a lot but unable to find proper answer. I also looked upon https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_82 and followed it properly but I think I still miss something.

    Please suggest me something.

    2 Solutions Collect From Internet About “import sqlite3.h error: include of non-modular header inside framework module”

    As far as I know you can not directly import Objective-C files into Swift in a framework. But you could do it in another Objective-C classes in he same framework. So if you write an Objective-C class in your framework you will be able to include the header file directly into your class and use it.

    For the same purpose I ended up writing a wrapper class for sqlite.h in Objective-C and then access that in my Swift code. The header for wrapper class you write must be made public and added to your umbrella header.

    I wrote something like this:

    #ifndef SqlWrapper_h
    #define SqlWrapper_h
    
    struct sqlite3;
    
    BOOL OpenDatabaseWithFileName(NSString* databaseFileName, struct sqlite3** database);
    
    BOOL PrepareStatement(struct sqlite3* database,NSString *selectStatement,struct sqlite3_stmt** preparedStatement);
    
    BOOL StepStatement(struct sqlite3_stmt* compiledStatement);
    
    BOOL FinalizeStatement(struct sqlite3_stmt* compiledStatement);
    
    NSInteger NumberOfRowsAffected(struct sqlite3* database);
    
    NSInteger LastInsertedRowID(struct sqlite3* database);
    
    NSInteger GetColumnCount(struct sqlite3_stmt* compiledStatement);
    
    const unsigned char* GetColumnValue(struct sqlite3_stmt* compiledStatement,int index);
    
    NSInteger GetColumnValueInInteger(struct sqlite3_stmt* compiledStatement,int index);
    
    double GetColumnValueInDouble(struct sqlite3_stmt* compiledStatement,int index);
    
    BOOL CloseDatabase(struct sqlite3* database);
    
    #endif
    

    Each of these function wraps sqlite3 methods. These could be called from your Swift classes in the same framework.

    I have taken an objective c file and somewhat customised it.

    Sqlite3Wrapper.h

    #ifndef SqliteWrap_Sqlite3Wrapper_h
    #define SqliteWrap_Sqlite3Wrapper_h
    
    struct sqlite3;
    @class SqlStatement;
    
    @interface Sqlite3Wrapper : NSObject
    
    -(id)initWithFileName: (NSString*) databaseFileName;
    
    -(BOOL) openDatabase;
    
    -(BOOL) closeDatabase;
    
    -(BOOL) isOpen;
    
    -(BOOL) executeStatement: (NSString*) sqlStatement;
    
    -(SqlStatement*) prepareStatement: (NSString*) sqlStatement;
    
    @end
    
    #endif
    

    Sqlite3Wrapper.m

    #import <Foundation/Foundation.h>
    #import <sqlite3.h>
    
    #import "Sqlite3Wrapper.h"
    #import "SqlStatement.h"
    
    @implementation Sqlite3Wrapper {
        sqlite3* _database;
        NSString* _databaseFileName;
    }
    
    -(id) initWithFileName:(NSString *)databaseFileName {
        self = [super init];
        if (self) {
            _databaseFileName = databaseFileName;
        }
        return self;
    }
    
    -(BOOL) openDatabase {
        int returnValue = sqlite3_open([_databaseFileName UTF8String], &_database);
        if (returnValue == SQLITE_OK) {
            return YES;
        }
    
        return NO;
    }
    
    -(BOOL) closeDatabase {
        if (_database) {
            if (sqlite3_close(_database) == SQLITE_OK) {
                _database = nil;
                return YES;
            }
        }
        return NO;
    }
    
    -(BOOL) isOpen {
        return (_database != nil);
    }
    
    -(BOOL) executeStatement: (NSString *)sqlStatement {
        if (_database == nil) {
            return NO;
        }
    
        return (sqlite3_exec(_database, [sqlStatement UTF8String], nil, nil, nil) == SQLITE_OK);
    
    //    sqlite3_stmt* statement;
    //    if (sqlite3_prepare_v2(_database, [sqlStatement UTF8String], -1, &statement, nil) == SQLITE_OK) {
    //        BOOL success = (sqlite3_step(statement) == SQLITE_OK);
    //        sqlite3_finalize(statement);
    //        return success;
    //    }
    //    return NO;
    }
    
    -(SqlStatement*) prepareStatement:(NSString *)sqlStatement {
        if (_database == nil) {
            return nil;
        }
    
        sqlite3_stmt* pStmt = nil;
        if (sqlite3_prepare_v2(_database, [sqlStatement UTF8String], -1, &pStmt, nil) == SQLITE_OK) {
            return [[SqlStatement alloc] initWithStatement: pStmt];
        }
    
        return nil;
    }
    
    
    @end
    

    I am using this wrapper file and created a swift file.

    Logger.swift

    import Foundation
    
    public class Logger {
        var dbWrapper:Sqlite3Wrapper
        var dataAccess = [String:AnyObject]()
    
        public init(dbName:String) {
            let docDirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
            let dbPath:NSString = docDirPath.stringByAppendingString(dbName)
    
            let fileManager:NSFileManager = NSFileManager.defaultManager()
            dbWrapper = Sqlite3Wrapper(fileName: dbName)
            if !fileManager.fileExistsAtPath(dbPath) {
                if dbWrapper.openDatabase() == false {
                    NSLog("Database not opened")
                    let sql:NSString = "CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)"
                    if dbWrapper.executeStatement(sql) {
                        NSLog("Table Created")
                    }
                    dbWrapper.closeDatabase()
                } else {
                    NSLog("Database opened")
                }
            } else {
                NSLog("Database exists")
            }
        }
    
        public func open() -> Bool {
            return dbWrapper.openDatabase()
        }
    
        public func test(dbName:NSString) {
            let docDirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
            let dbPath:NSString = docDirPath.stringByAppendingString(dbName)
    
            let fileManager:NSFileManager = NSFileManager.defaultManager()
    
            if !fileManager.fileExistsAtPath(dbPath) {
                if Sqlite3Wrapper(fileName: dbPath) == false {
                    NSLog("Database not opened")
                    let sql:NSString = "CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)"
                    if dbWrapper.executeStatement(sql) {
                        NSLog("Table Created")
                    }
                    dbWrapper.closeDatabase()
                } else {
                    NSLog("Database opened")
                }
            } else {
                NSLog("Database exists")
            }
        }
    }
    
    public func logMessage(message: NSString ) {
        NSLog("Message is printed")
    }
    
    public func createDatabase(dbName: NSString ) {
        Data(dbName: dbName)
    }
    

    Last 2 functions createDatabase and logMessage are just temporary to test if I can access these functions directly or not.

    I have created an “Aggregated Target” as well for universal framework for both device and simulator. But when I use this universal framework, I am unable to import Logger and receives error “No such module ‘Logger'”. But when I package framework for device and try to add the same framework, I am able to do the import thing.

    Finally, the issue is once I import Logger, I am unable to access any function or Data class from the framework. I only can access Sqlite3Wrapper which is written in Objective C. I want to use that Data class or public functions.

    Please let me know if you think I have doing something wrong.