2021年5月23日日曜日

共有ライブラリをつかって https://taiyakisun.hatenablog.com/entry/20150506/1430896155

 C/C++でのお話です。

忘れがちなのでまとめておきます。

備忘録

共有ライブラリ作成時
  • VC++ではexportする関数毎に__declspec(dllexport)が必要になるが、gccの場合はstaticが付与されていなければ自動的に公開になるため不要
  • 共有ライブラリ(拡張子so)のファイル名には先頭に必ずlibをつける(例:sharedlib.cならlibsharedlib.so)
  • -fPIC」(Position Independent Code)オプションをつけてコンパイルした方がよい
共有ライブラリ使用時
  • 先頭のlibと拡張子.soを除いた名前を指定する(例:libsharedlib.soなら-l sharedlib)
  • ヘッダファイルやライブラリパスの場所を指定する-Iや-Lはスペースを空けずにオプションの直後にパスを書く(例:-I/home/sample -L./lib)

共有ライブラリの作成

#include <stdio.h>

int add( int n1, int n2 )
{
    printf( "result:%d + %d = %d\n", n1, n2, n1+n2 );
    return n1+n2;
}
gcc -shared -fPIC -o libsharedlib.so sharedlib.c

共有ライブラリの使用

#include <stdio.h>

int main()
{
  int n1 = 10;
  int n2 = 20;

  printf( "caller:%d + %d = %d\n", n1, n2, add(n1,n2) );

  return 0;
}
gcc -I./ -L./ -o main main.c -lsharedlib

正しく実行されれば以下が標準出力に出力されます。

result:10 + 20 = 30
caller:10 + 20 = 30

もし共有ファイル名の先頭が「lib」でない場合は以下のように
共有ライブラリが見つけられずリンカーエラーになってしまいます。

/usr/bin/ld: cannot find -lsharedlib

実行ファイル実行時

ライブラリのパスが通っている場所に共有ライブラリを置くか、
もしくは以下のように環境変数LD_LIBRARY_PATHにパスを指定してから実行します。

自注)この設定は、恒久的でなくシェルを閉じるとなくなる!

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./

これを実施しないと以下のように共有ライブラリが
見つからない旨のエラーメッセージが出力されます。

./main: error while loading shared libraries: libsharedlib.so: cannot open shared object file: No such file or directory

2021年5月8日土曜日

mono :: sqlite3 and httpserver by c#

https://www.milkmemo.com/entry/ubuntu_csharp_kaihatukankyo :: mono-complete

-- sqlite3 TestData.db < Products.sql
--
-- Products テーブル削除
drop table if exists Products;

-- Products テーブル作成
create table Products(
    ProductID int not null primary key,
    ProductName text not null,
    Price numeric null,
    ProductDescription text null);

-- INSERT 実行1
insert into Products 
           (ProductID, ProductName, Price, ProductDescription)
    values (1, 'Clamp', 12.48, 'Workbench clamp');

-- INSERT 実行2 カラムの順番を変えたパターン
insert into Products 
           (ProductName, ProductID, Price, ProductDescription)
    values ('Screwdriver', 50, 3.17, 'Flat head');

-- INSERT 実行3 カラムリスト指定なし、入力値リストはカラム順パターン
insert into Products
    values (75, 'Tire Bar', NULL, 'Tool for changing tires.');

-- INSERT 実行4 ProductDescription カラムの指定なしパターン
insert into Products (ProductID, ProductName, Price)
    values (3000, '3mm Bracket', .52);

-- UPDATE 実行
update Products
    set ProductName = 'Flat Head Screwdriver'
    where ProductID = 50;

-- 確認用 SELECT 実行
select * from Products;


using System;
using System.Data;
using Mono.Data.Sqlite;

namespace SqliteExample
{
  public class NewType
  {
    public static void Main(string[] args)
    {
      // 接続文字列
      string constr 
        = "Data Source=/home/sta/data/TestData.db";
      // SQL文字列
      string sqlstr = "SELECT ProductID, ProductName, " +
                        "Price, ProductDescription " +
                      "FROM Products";

      // 1.DBコネクションオブジェクト作成
      using (IDbConnection dbcon = new SqliteConnection(constr))
      {
        // 2.DBコネクションオープン
        dbcon.Open();

        try
        {
          // 3.DBコマンドオブジェクト作成
          using (IDbCommand dbcmd = dbcon.CreateCommand())
          {
            dbcmd.CommandText = sqlstr;

            // 4.DBコマンド実行
            using (IDataReader reader = dbcmd.ExecuteReader())
            {
              while(reader.Read())
              {
                string ProductID = reader[0].ToString();
                string ProductName = reader[1].ToString();

                string Price = string.Empty;
                if(reader[2] != null)
                {
                  Price = reader[2].ToString();
                }

                string ProductDescription = string.Empty;
                if(reader[3] != null)
                {
                  ProductDescription = reader[3].ToString();
                }

                Console.WriteLine(
                  "ID:{0} NAME:{1} PRICE:{2} DESCRIPTION:{3}", 
                  ProductID, ProductName, Price, ProductDescription);
              }
            }
          }
        }
        finally
        {
          if (dbcon != null)
          {
            // 5.DBコネクションクローズ
            dbcon.Close();
          }
        }
      }
    }
  }
}
/*
 * ビルド:
 *
 *   mcs new.cs -r:System.Data.dll -r:Mono.Data.Sqlite.dll
 *
 * 実行:
 *
 *   mono new.exe
 */

https://codezine.jp/article/detail/2823?p=2

https://codezine.jp/article/detail/2851?p=5 about monodevelop

------------------------------------------------------------------------

 

// Filename: HttpServer.cs
// Author: Benjamin N. Summerton <define-private-public>
// License: Unlicense (http://unlicense.org/)
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Threading.Tasks;
namespace HttpListenerExample
{
class HttpServer
{
public static HttpListener listener;
public static string url = "http://localhost:8000/";
public static int pageViews = 0;
public static int requestCount = 0;
public static string pageData =
"<!DOCTYPE>" +
"<html>" +
" <head>" +
" <title>HttpListener Example</title>" +
" </head>" +
" <body>" +
" <p>Page Views: {0}</p>" +
" <form method=\"post\" action=\"shutdown\">" +
" <input type=\"submit\" value=\"Shutdown\" {1}>" +
" </form>" +
" </body>" +
"</html>";
public static async Task HandleIncomingConnections()
{
bool runServer = true;
// While a user hasn't visited the `shutdown` url, keep on handling requests
while (runServer)
{
// Will wait here until we hear from a connection
HttpListenerContext ctx = await listener.GetContextAsync();
// Peel out the requests and response objects
HttpListenerRequest req = ctx.Request;
HttpListenerResponse resp = ctx.Response;
// Print out some info about the request
Console.WriteLine("Request #: {0}", ++requestCount);
Console.WriteLine(req.Url.ToString());
Console.WriteLine(req.HttpMethod);
Console.WriteLine(req.UserHostName);
Console.WriteLine(req.UserAgent);
Console.WriteLine();
// If `shutdown` url requested w/ POST, then shutdown the server after serving the page
if ((req.HttpMethod == "POST") && (req.Url.AbsolutePath == "/shutdown"))
{
Console.WriteLine("Shutdown requested");
runServer = false;
}
// Make sure we don't increment the page views counter if `favicon.ico` is requested
if (req.Url.AbsolutePath != "/favicon.ico")
pageViews += 1;
// Write the response info
string disableSubmit = !runServer ? "disabled" : "";
byte[] data = Encoding.UTF8.GetBytes(String.Format(pageData, pageViews, disableSubmit));
resp.ContentType = "text/html";
resp.ContentEncoding = Encoding.UTF8;
resp.ContentLength64 = data.LongLength;
// Write out to the response stream (asynchronously), then close it
await resp.OutputStream.WriteAsync(data, 0, data.Length);
resp.Close();
}
}
public static void Main(string[] args)
{
// Create a Http server and start listening for incoming connections
listener = new HttpListener();
listener.Prefixes.Add(url);
listener.Start();
Console.WriteLine("Listening for connections on {0}", url);
// Handle requests
Task listenTask = HandleIncomingConnections();
listenTask.GetAwaiter().GetResult();
// Close the listener
listener.Close();
}
}
}