memo
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 5 モーダル</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<!-- モーダルを開くボタン -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
モーダルを開く
</button>
<!-- モーダルのHTML -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">モーダルタイトル</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
ここに内容を書きます。
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">閉じる</button>
<button type="button" class="btn btn-primary">保存する</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
function hasModeAbc(url) {
try {
const parsedUrl = new URL(url);
// searchParamsからmodeの値を取得して判定
return parsedUrl.searchParams.get('mode') === 'abc';
} catch (error) {
// URLのパースに失敗した場合はfalseを返す
return false;
}
}
// 使用例
console.log(hasModeAbc("https://example.com/?mode=abc")); // true
console.log(hasModeAbc("https://example.com/?foo=bar&mode=abc")); // true
console.log(hasModeAbc("https://example.com/?mode=abc&foo=bar")); // true
console.log(hasModeAbc("https://example.com/?mode=xyz&foo=bar")); // false
console.log(hasModeAbc("https://example.com/?foo=bar&mode=abc&baz=qux")); // true
その2
from openpyxl import load_workbook
from openpyxl.worksheet.datavalidation import DataValidation
def copy_data_validation(ws, fromCell, toCell):
"""
指定したセルのデータバリデーション(入力規則)をコピーする関数
:param ws: 対象のワークシート
:param fromCell: コピー元のセル(例: "A1")
:param toCell: コピー先のセル(例: "B1")
"""
# コピー元セルのデータバリデーションを取得
for dv in ws.data_validations.dataValidation:
if fromCell in dv.cells:
original_dv = dv
break
else:
raise ValueError(f"{fromCell} にデータバリデーションが見つかりません")
# プルダウンリスト(リスト制約)の場合
if original_dv.type == "list":
new_dv = DataValidation(
type="list",
formula1=original_dv.formula1, # リストの定義をコピー
allowBlank=original_dv.allowBlank,
showDropDown=original_dv.showDropDown,
showErrorMessage=original_dv.showErrorMessage,
showInputMessage=original_dv.showInputMessage,
prompt=original_dv.prompt,
promptTitle=original_dv.promptTitle,
error=original_dv.error,
errorTitle=original_dv.errorTitle,
errorStyle=original_dv.errorStyle
)
# コピー先セルに適用
new_dv.add(toCell)
# ワークシートにデータバリデーションを追加
ws.add_data_validation(new_dv)
else:
raise ValueError(f"{fromCell} のデータバリデーションはリスト型(プルダウン)ではありません")
# 使用例
wb = load_workbook("sample.xlsx")
ws = wb.active
# A1 から B1 に入力規則(プルダウン)をコピー
copy_data_validation(ws, "A1", "B1")
# 保存
wb.save("sample_copy.xlsx")
from openpyxl import load_workbook
from openpyxl.worksheet.datavalidation import DataValidation
# グローバル変数としてデータバリデーションを保持
original_dv = None
def copy_data_validation(ws, fromCell, toCell):
"""
指定したセルのデータバリデーション(入力規則)をコピーする関数
1回目は `original_dv` を取得して保持し、2回目以降は再利用する。
:param ws: 対象のワークシート
:param fromCell: コピー元のセル(例: "A1")
:param toCell: コピー先のセル(例: "B1")
"""
global original_dv # グローバル変数を使用
# 1回目の実行時はコピー元のデータバリデーションを取得
if original_dv is None:
for dv in ws.data_validations.dataValidation:
if fromCell in dv.cells:
original_dv = dv
break
else:
raise ValueError(f"{fromCell} にデータバリデーションが見つかりません")
# 直接コピー先セルに追加
original_dv.add(toCell)
# 再度ワークシートにデータバリデーションを適用(必須)
ws.add_data_validation(original_dv)
# 使用例
wb = load_workbook("sample.xlsx")
ws = wb.active
# 1回目のコピー(グローバル変数に保持)
copy_data_validation(ws, "A1", "B1")
# 2回目以降のコピー(`original_dv` を再利用)
copy_data_validation(ws, "A1", "C1")
copy_data_validation(ws, "A1", "D1")
# 保存
wb.save("sample_copy.xlsx")
from openpyxl import load_workbook
from openpyxl.worksheet.datavalidation import DataValidation
# グローバル変数としてデータバリデーションを保持
original_dv = None
def copy_data_validation(ws, fromCell, toCell):
"""
指定したセルのデータバリデーション(入力規則)をコピーする関数
`fromCell` と `toCell` は `ws.cell(row=y, column=x)` で取得されたセルオブジェクト
:param ws: 対象のワークシート
:param fromCell: コピー元のセルオブジェクト(例: ws.cell(row=1, column=1))
:param toCell: コピー先のセルオブジェクト(例: ws.cell(row=1, column=2))
"""
global original_dv # グローバル変数を使用
# 1回目の実行時はコピー元のデータバリデーションを取得
if original_dv is None:
cell_ref = fromCell.coordinate # A1 形式のセル参照
for dv in ws.data_validations.dataValidation:
if cell_ref in dv.cells:
original_dv = dv
break
else:
raise ValueError(f"{cell_ref} にデータバリデーションが見つかりません")
# 直接コピー先セルに追加
original_dv.add(toCell.coordinate)
# 再度ワークシートにデータバリデーションを適用(必須)
ws.add_data_validation(original_dv)
# 使用例
wb = load_workbook("sample.xlsx")
ws = wb.active
# A1 から B1 に入力規則をコピー
copy_data_validation(ws, ws.cell(row=1, column=1), ws.cell(row=1, column=2))
# C1, D1 へもコピー
copy_data_validation(ws, ws.cell(row=1, column=1), ws.cell(row=1, column=3))
copy_data_validation(ws, ws.cell(row=1, column=1), ws.cell(row=1, column=4))
# 保存
wb.save("sample_copy.xlsx")
ExcelFitToPageSetter
from openpyxl import load_workbook
def set_fit_to_page(ws):
"""
Excelの「次のページ数に合わせて印刷」を有効にし、
縦のページ数の制限を解除する(空白にする)。
:param ws: ワークシートオブジェクト
"""
# 次のページ数に合わせて印刷を有効化
ws.page_setup.fitToPage = True
# 横を1ページに収める
ws.page_setup.fitToWidth = 1
# 縦のページ数を「空白」にする(無制限)
ws.page_setup.fitToHeight = None
# 使用例
wb = load_workbook("sample.xlsx")
ws = wb.active
# 設定を適用
set_fit_to_page(ws)
# 保存
wb.save("sample_modified.xlsx")
from openpyxl import load_workbook
# ワークブックを読み込む
wb = load_workbook("sample.xlsx")
# ワークシートを取得する
ws = wb["Sheet1"]
# ページ設定を行う
ws.page_setup.fitToWidth = 1 # 横方向に1ページに収める
ws.page_setup.fitToHeight = 0 # 縦方向のページ数を無制限にする
# ワークブックを保存する
wb.save("sample_modified.xlsx")
from openpyxl import load_workbook
def copy_sheet(file_path, source_sheet_name, target_sheet_name):
# Excelブックを読み込み
wb = load_workbook(file_path)
# コピー元のシートを取得
if source_sheet_name not in wb.sheetnames:
raise ValueError(f"シート '{source_sheet_name}' が存在しません。")
source_sheet = wb[source_sheet_name]
# シートをコピー
copied_sheet = wb.copy_worksheet(source_sheet)
# コピーしたシートの名称を設定
copied_sheet.title = target_sheet_name
# ファイルを上書き保存
wb.save(file_path)
wb.close()
# 使用例
copy_sheet("sample.xlsx", "Sheet1", "Sheet1_Copy")
from openpyxl import load_workbook
from openpyxl.worksheet.worksheet import Worksheet
def copy_sheet_with_settings(file_path, source_sheet_name, target_sheet_name):
# Excelブックを読み込み
wb = load_workbook(file_path)
# コピー元のシートを取得
if source_sheet_name not in wb.sheetnames:
raise ValueError(f"シート '{source_sheet_name}' が存在しません。")
source_sheet = wb[source_sheet_name]
# シートをコピー
copied_sheet = wb.copy_worksheet(source_sheet)
copied_sheet.title = target_sheet_name
# 印刷範囲のコピー
if source_sheet.print_area:
copied_sheet.print_area = source_sheet.print_area
# 印刷オプションのコピー(ヘッダー、フッター、グリッド線、拡大縮小など)
copied_sheet.print_options.horizontalCentered = source_sheet.print_options.horizontalCentered
copied_sheet.print_options.verticalCentered = source_sheet.print_options.verticalCentered
copied_sheet.print_options.gridLines = source_sheet.print_options.gridLines
copied_sheet.print_options.headings = source_sheet.print_options.headings
# シートビュー(標準ビューや改ページプレビューの状態)をコピー
if hasattr(source_sheet, 'views') and source_sheet.views:
copied_sheet.views = source_sheet.views
# ファイルを上書き保存
wb.save(file_path)
wb.close()
# 使用例
copy_sheet_with_settings("sample.xlsx", "Sheet1", "Sheet1_Copy")
from openpyxl import load_workbook
def select_all_sheets_and_set_first_active(file_path):
# Excelブックを開く
wb = load_workbook(file_path)
# 全シートの選択を解除
for ws in wb.worksheets:
ws.sheet_view.tabSelected = False
# すべてのシートを選択状態にする
for ws in wb.worksheets:
ws.sheet_view.tabSelected = True
# 一番左のシートをアクティブにする
wb.active = 0 # 最初のシートをアクティブに設定
# ファイルを保存
wb.save(file_path)
wb.close()
# 使用例
select_all_sheets_and_set_first_active("sample.xlsx")
Excelの仕様
Excelでは「選択済みのシート は tabSelected=True のシートが 1つ以上ある状態」
ただし、「アクティブなシートは必ず1つだけ」 でなければならない
もし、すでに tabSelected=True のシートがあって、別のシートを tabSelected=True にすると どのシートがアクティブなのか不明確になる
openpyxlの内部動作
openpyxl は「アクティブなシートが必ず1つである」ことを期待している
tabSelected=True を複数のシートに設定するとき、一度 すべて False にしないと、どのシートがアクティブかの整合性が取れなくなる可能性がある
Excel のUIでは、 手動で「すべてのシートを選択」すると、自動的に1つのシートがアクティブになる 仕様になっているため、これを openpyxl でも再現するには、 一度すべて False にしてから True にする方が安全
/*
画面リロードから再表示完了までスピナーを表示するようにしたため
途中でjavascriptエラーが発生時に、スピナーが表示されっぱなしになることを防ぎたい。
( 処理に時間がかかっているのか、エラーがあるのか判断できなくなるから )
そのため、catchしてないjavascriptの例外を捕獲して
スピナーを消す。
その際、エラーの通知、および、詳細なデバッグ情報をconsole.error()をしておく
*/
window.addEventListener('error', function (event) {
let errorMessage = getErrorMessageOnGlobalError(event);
let isAlert = true;
/*
videoタグをカルーセルに入れてから、
カルーセルでページ切り替え中に、時々、
message : ResizeObserver loop completed with undelivered notifications.
のようなエラーメッセージで、ここに飛んでくる。原因不明である。
ただ、ここにエラーが飛んでくるだけで画面表示がおかしくなったりもしない
特に実害がないため、
ブラウザのデバッガーで見れるコンソールには出力しておくが、alert表示をしないことにした。
*/
let specialError00100 = errorMessage.includes('ResizeObserver loop completed');
if(specialError00100) {
isAlert = false;
}
console.error('エラーが発生しました:', errorMessage);
if(isAlert) {
alert('エラーが発生しました');
}
// スピナーを消す
hideSpinner();
});
/**
* 「window.addEventListener('error', function (event) {」
* グローバルにcatchしてないjavascript例外を捕獲した時のeventオブジェクトより
* 詳細なデバッグ情報のあるerrorMessageを取得する。
*/
function getErrorMessageOnGlobalError(event) {
let errorMessage = `message : ${event.message} source : ${event.filename}:${event.lineno}:${event.colno}`;
if (event.error) {
if (event.error.stack) {
errorMessage += `stacktrace : ${event.error.stack}`;
}
}
return errorMessage;
}
import pandas as pd
import copy
# 検証用のDataFrame(コピー先の列は未定義)
df = pd.DataFrame({
'col1': [[1, 2], [3, 4], [5, 6]] # リストを含むケース
})
# 'col2' に 'col1' の完全コピーを作成(deep copy)
df['col2'] = df['col1'].apply(lambda x: copy.deepcopy(x))
# 'col1' を変更して 'col2' に影響があるかを確認
df.at[0, 'col1'].append(99)
# 結果の比較
df[['col1', 'col2']]
import pandas as pd
import copy
# ✅ 実装:完全コピー関数(col1, col2 に対し、None/空文字ならそれぞれ別のデフォルト値を適用)
def format_and_combine(row, col1_name, col2_name, default_value1, default_value2):
val1 = str(row[col1_name]) if row[col1_name] not in [None, ''] else default_value1
val2 = str(row[col2_name]) if row[col2_name] not in [None, ''] else default_value2
return copy.deepcopy(f"{val1}_{val2}")
# ✅ 検証用データ(文字列、None、空文字、数値、ゼロ埋めなど多様なケースを網羅)
df = pd.DataFrame({
'col1': [123456, None, '', '000001', 'abcdef', 0],
'col2': ['654321', '', None, 999999, 0, '']
})
# ✅ col3 を新規作成(default値も個別に指定)
df['col3'] = df.apply(lambda row: format_and_combine(
row, 'col1', 'col2', 'DEFAULT1', 'DEFAULT2'
), axis=1)
結果
col1 col2 col3
0 123456 654321 123456_654321
1 None DEFAULT1_DEFAULT2
2 None DEFAULT1_DEFAULT2
3 000001 999999 000001_999999
4 abcdef 0 abcdef_0
5 0 0_DEFAULT2
import pandas as pd
import copy
# ✅ 元の関数イメージ(deepcopy ありとなしを比較)
def format_and_combine_with_deepcopy(row, col1_name, col2_name, default_value1, default_value2):
val1 = str(row[col1_name]) if row[col1_name] not in [None, ''] else default_value1
val2 = str(row[col2_name]) if row[col2_name] not in [None, ''] else default_value2
return copy.deepcopy(f"{val1}_{val2}")
def format_and_combine_without_deepcopy(row, col1_name, col2_name, default_value1, default_value2):
val1 = str(row[col1_name]) if row[col1_name] not in [None, ''] else default_value1
val2 = str(row[col2_name]) if row[col2_name] not in [None, ''] else default_value2
return f"{val1}_{val2}"
# 検証用の単一行DataFrame(値・None・空文字含む)
df = pd.DataFrame({
'col1': ['abc'],
'col2': ['def']
})
# 両方の関数で結果を生成
result_with_deepcopy = df.apply(lambda row: format_and_combine_with_deepcopy(
row, 'col1', 'col2', 'DEFAULT1', 'DEFAULT2'), axis=1)[0]
result_without_deepcopy = df.apply(lambda row: format_and_combine_without_deepcopy(
row, 'col1', 'col2', 'DEFAULT1', 'DEFAULT2'), axis=1)[0]
# オブジェクトID(メモリアドレス)比較、内容比較
id_with = id(result_with_deepcopy)
id_without = id(result_without_deepcopy)
is_same_id = id_with == id_without
is_same_value = result_with_deepcopy == result_without_deepcopy
# val1/val2 の段階で deepcopy が不要かを確認するために、それぞれの id も取得
# val1/val2 自体も文字列として生成されており、それが deepcopy 不要かの確認
def get_val_ids(row):
val1 = str(row['col1']) if row['col1'] not in [None, ''] else 'DEFAULT1'
val2 = str(row['col2']) if row['col2'] not in [None, ''] else 'DEFAULT2'
return id(val1), id(val2)
val1_id, val2_id = df.apply(get_val_ids, axis=1)[0]
# deepcopy 前の文字列の ID 取得(str(...) または default で代入された値)
val1_id, val2_id, id_with, id_without, is_same_id, is_same_value
結果
(139432584242336,
139432571161536,
139432493964928,
139430791448448,
False,
True)
# ✅ 修正:values_match の判定ミスを修正
import pandas as pd
# ✅ 定数定義(default 値として使用)
DEFAULT_VALUE1 = 'XXXXXX'
DEFAULT_VALUE2 = 'XXXXXX'
# ✅ col1, col2 から col3 を作成(deepcopy 不要)
def format_and_combine(row, col1_name, col2_name, default_value1, default_value2):
val1 = str(row[col1_name]) if row[col1_name] not in [None, ''] else default_value1
val2 = str(row[col2_name]) if row[col2_name] not in [None, ''] else default_value2
return f"{val1}_{val2}"
# ✅ 検証用データ(col3 は未定義)
df = pd.DataFrame({
'col1': [123456, None, '', '000001', 'abcdef', 0],
'col2': ['654321', '', None, 999999, 0, '']
})
# ✅ col3 を新規作成(未定義状態から)
df['col3'] = df.apply(lambda row: format_and_combine(
row, 'col1', 'col2', DEFAULT_VALUE1, DEFAULT_VALUE2
), axis=1)
# ✅ 動作検証(値の確認)
expected_values = [
"123456_654321",
"XXXXXX_XXXXXX",
"XXXXXX_XXXXXX",
"000001_999999",
"abcdef_0",
"0_XXXXXX"
]
# 実際の値と期待値がすべて一致しているか確認
values_match = df['col3'].tolist() == expected_values
# col3 のオブジェクトID(新しい文字列オブジェクトが作られているか)
col3_ids = df['col3'].apply(id).tolist()
# col3 の要素ごとの deep copy 検証(各値が新しいオブジェクトになっているか)
deep_copy_check = all(col3_ids[i] != id(expected_values[i]) for i in range(len(expected_values)))
# ✅ 検証結果
values_match, deep_copy_check, df
結果
(True,
True,
col1 col2 col3
0 123456 654321 123456_654321
1 None XXXXXX_XXXXXX
2 None XXXXXX_XXXXXX
3 000001 999999 000001_999999
4 abcdef 0 abcdef_0
5 0 0_XXXXXX)
dataframeのto_excel()
をしたときに、
ValueError: Excel does not support datatimes with timezones. Please ensure that datetimes are timezone unaware before writing to Excel
のエラーになる
dataframeの行数、列数が大量にあるため、どの行のどの列か特定できない
しかし、エラーがでてるのは、おそらく、日時の項目ではないかと思われる
dataframeのto_excel()をしたのは、他の列の値について、行列がどうなってるかをデバッグのために知りたいからで
エラーになってる日時の値など、とりあえず、今、どうでもいいから、Excel出力したい
そこで、dataframeについて、上記のエラーが出る箇所
どこか、わからないが、いっきに、to_excel()ではエラーにならない。別の値に変換後のdataframeに対して
to_excel()がしたい
# セッションがリセットされたため再実行
import pandas as pd
import pytz
# ✅ 検証用の DataFrame:timezone-aware datetime を含む
df = pd.DataFrame({
'id': [1, 2],
'created_at': [
pd.Timestamp('2023-01-01 12:00:00', tz='UTC'),
pd.Timestamp('2023-01-02 13:30:00', tz='UTC')
],
'name': ['Alice', 'Bob']
})
# ✅ 関数:timezone-aware な datetime を timezone-unaware に変換
def remove_timezone_in_df(df):
for col in df.columns:
if pd.api.types.is_datetime64_any_dtype(df[col]):
if hasattr(df[col].dt, 'tz') and df[col].dt.tz is not None:
df[col] = df[col].dt.tz_localize(None)
return df
# ✅ タイムゾーンを除去した新しい DataFrame を作成
df_cleaned = remove_timezone_in_df(df.copy())
# ✅ Excel への保存を試行
output_path = "/mnt/data/cleaned_output.xlsx"
df_cleaned.to_excel(output_path, index=False)
# ✅ 出力結果の検証
output_path, df_cleaned.dtypes, df_cleaned.head()
結果
('/mnt/data/cleaned_output.xlsx',
id int64
created_at datetime64[ns]
name object
dtype: object,
id created_at name
0 1 2023-01-01 12:00:00 Alice
1 2 2023-01-02 13:30:00 Bob)
# セッションがリセットされたため再実行
import pandas as pd
# ✅ 検証用データフレーム("foo" は存在しない)
df = pd.DataFrame({
'col1': ['bar', 'baz', 'qux']
})
# ✅ 一般論としての判定式:col1 が "foo" の行が 0 行かどうか
is_zero_foo = (df['col1'] == 'foo').sum() == 0
# ✅ 結果を表示
is_zero_foo, df
結果
(True,
col1
0 bar
1 baz
2 qux)
import pandas as pd
import numpy as np
# サンプルデータフレームの作成
data = {'A': range(1, 105), 'B': range(105, 209)}
df = pd.DataFrame(data)
# DataFrameBatchGenerator クラスの定義
class DataFrameBatchGenerator:
def __init__(self, dataframe, batch_size=10):
"""
コンストラクタ。
:param dataframe: 分割対象のPandas DataFrame。
:param batch_size: 各バッチの行数。デフォルトは10。
"""
self.dataframe = dataframe
self.batch_size = batch_size
self.total_rows = len(dataframe)
def __iter__(self):
"""
イテレータを返すメソッド。
"""
self.current_index = 0
return self
def __next__(self):
"""
次のバッチを返すメソッド。
:return: DataFrameのバッチ。
:raises StopIteration: データがもう残っていない場合に発生。
"""
if self.current_index >= self.total_rows:
raise StopIteration
start_idx = self.current_index
end_idx = min(start_idx + self.batch_size, self.total_rows)
batch = self.dataframe.iloc[start_idx:end_idx]
self.current_index = end_idx
return batch
# バッチサイズの定義
batch_size = 10
# DataFrameBatchGenerator のインスタンス化
batch_generator = DataFrameBatchGenerator(df, batch_size)
# バッチ処理とビュー・コピーの検証
for i, batch in enumerate(batch_generator):
# メモリ共有の確認
is_view = np.shares_memory(df.values, batch.values)
# 結果の出力
print(f"バッチ {i+1}: 行 {i*batch_size} から {i*batch_size + len(batch) - 1}")
print(f"このバッチはビューか?: {'はい' if is_view else 'いいえ'}")
print('-' * 50)
コードの説明:
サンプルデータフレームの作成:
2列('A'と'B')を持つデータフレームdfを作成しています。
DataFrameBatchGenerator クラスの定義:
以前に提供したクラスと同一です。
バッチ処理とビュー・コピーの検証:
DataFrameBatchGenerator を使用してデータフレームをバッチに分割します。
各バッチに対して、np.shares_memory(df.values, batch.values) を用いて、元のデータフレームとバッチがメモリを共有しているかを確認します。
各バッチの範囲と、ビューであるかどうかの結果をコンソールに出力します。
注意点:
Pandasのバージョンによる挙動の違い:
Pandasのバージョンや設定によって、スライス時にビューが返されるかコピーが返されるかの挙動が異なる場合があります。
特に、Pandas 1.5以降ではCopy-on-Write (CoW)モードが導入され、部分取得時にコピーが作成される挙動がデフォルトとなっています。
np.shares_memory関数について:
この関数は、2つの配列がメモリを共有しているかを判定します。Trueが返された場合、2つの配列は同じメモリ領域を参照しており、変更が相互に影響します。Falseの場合、メモリを共有していないため、変更は相互に影響しません。
このコードを実行することで、ご自身の環境でのDataFrameBatchGeneratorの挙動を確認し、各バッチがビューまたはコピーのどちらであるかを把握することができます。
https://learn.microsoft.com/ja-jp/sql/connect/odbc/download-odbc-driver-for-sql-server
必要なパッケージのインストール:
sudo apt-get update
sudo apt-get install -y curl gnupg apt-transport-https
これにより、必要なツールとライブラリがインストールされます。
MicrosoftのGPGキーのインポート:
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
これにより、Microsoftのパッケージを信頼するためのGPGキーがシステムに追加されます。
Microsoftリポジトリの追加:
curl https://packages.microsoft.com/config/ubuntu/24.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list
これにより、Microsoftのパッケージリポジトリがシステムのソースリストに追加されます。
パッケージリストの更新とODBCドライバのインストール:
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18
これにより、Microsoft ODBC Driver 18 for SQL Serverがインストールされます。
sudo apt update
sudo apt install unixodbc
これがlibodbc.so.2を提供する
dpkg -L unixodbc | grep libodbc.so.2
✅ MicrosoftのGPGキー・APT設定などをクリーンに削除する手順
🔹 1. MicrosoftのAPTリストを削除
bash
コピーする
編集する
sudo rm /etc/apt/sources.list.d/mssql-release.list
もし .list.save や .list.distUpgrade のようなファイルもあれば削除してOK:
bash
コピーする
編集する
sudo rm /etc/apt/sources.list.d/mssql-release.list.*
🔹 2. GPGキーの削除
キーをどこに保存したかにより、以下どちらか:
▸ /usr/share/keyrings/ に保存した場合:
bash
コピーする
編集する
sudo rm /usr/share/keyrings/microsoft-prod.gpg
▸ apt-key で追加した場合(古いやり方):
以下でキーのIDを確認:
bash
コピーする
編集する
apt-key list
Microsoft関連のキー(Microsoft (Release signing) <gpgsecurity@microsoft.com>)のIDを確認し、以下で削除:
bash
コピーする
編集する
sudo apt-key del <キーID>
例:
bash
コピーする
編集する
sudo apt-key del BC528686B50D79E339D3721CEB3E94ADBE1229CF
🔹 3. 不要になった .deb ファイルの削除(もし残っていれば)
bash
コピーする
編集する
rm ~/packages-microsoft-prod.deb 2>/dev/null
🔹 4. リポジトリキャッシュを更新
bash
コピーする
編集する
sudo apt update
これですべてクリーンな状態に戻せます。
必要があれば、Ubuntu標準のパッケージ(unixodbc など)もアンインストール案内できます。
続ける場合は「次の手順を教えて」と言ってください。
✅ 元に戻すために実行すべきコマンド(間違った構成の完全削除)
❶ MicrosoftのAPT設定を削除(おれが最初に言ったやつ)
bash
コピーする
編集する
sudo rm /etc/apt/sources.list.d/mssql-release.list
❷ GPGキーを削除(apt-keyで追加された場合)
bash
コピーする
編集する
sudo apt-key del EB3E94ADBE1229CF 2>/dev/null
※ 上記キーIDは Microsoft の公開鍵(もし違うIDの場合、apt-key list で確認してください)
❸ ダウンロードした .deb ファイルが残っていたら削除
bash
コピーする
編集する
rm -f packages-microsoft-prod.deb
❹ 間違ってインストールされたパッケージの削除
bash
コピーする
編集する
sudo apt remove --purge -y msodbcsql18 mssql-tools18
sudo apt autoremove -y
❺ bashrc 変更の取り消し(export PATH されていた場合)
bash
コピーする
編集する
sed -i '/\/opt\/mssql-tools18\/bin/d' ~/.bashrc
❻ APTキャッシュ更新
bash
コピーする
編集する
sudo apt update
sudo tee /etc/odbcinst.ini > /dev/null <<EOF
[ODBC Driver 18 for SQL Server]
Description=Microsoft ODBC Driver 18 for SQL Server
Driver=/opt/microsoft/msodbcsql18/lib64/libmsodbcsql-18.so
UsageCount=1
EOF
sudo apt install --reinstall -y msodbcsql18
公式
if ! [[ "20.04 22.04 24.04 24.10" == *"$(grep VERSION_ID /etc/os-release | cut -d '"' -f 2)"* ]];
then
echo "Ubuntu $(grep VERSION_ID /etc/os-release | cut -d '"' -f 2) is not currently supported.";
exit;
fi
# Download the package to configure the Microsoft repo
curl -sSL -O https://packages.microsoft.com/config/ubuntu/$(grep VERSION_ID /etc/os-release | cut -d '"' -f 2)/packages-microsoft-prod.deb
# Install the package
sudo dpkg -i packages-microsoft-prod.deb
# Delete the file
rm packages-microsoft-prod.deb
# Install the driver
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools18
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install -y unixodbc-dev
sudo tee -a /etc/odbc.ini > /dev/null <<EOF
[sqlservertest]
Driver = ODBC Driver 18 for SQL Server
Server = 127.0.0.1,1433
UID = <ユーザ名>
PWD = <パスワード>
Encrypt = no
TrustServerCertificate = yes
EOF
isql -v "Driver=ODBC Driver 18 for SQL Server;Server=127.0.0.1,1433;UID=sa;PWD=yourpassword;Encrypt=no;TrustServerCertificate=yes"
import pyodbc
conn_str = (
"DRIVER=ODBC Driver 18 for SQL Server;"
"SERVER=127.0.0.1,1433;"
"UID=admin;"
"PWD=yourpassword;"
"Encrypt=no;"
"TrustServerCertificate=yes;"
)
try:
conn = pyodbc.connect(conn_str, timeout=5)
print("Success!")
except Exception as e:
print("Failed:", e)
'ENGINE': 'sql_server.pyodbc',
'NAME': 'your_db_name',
'OPTIONS': {
'dsn': 'sqlservertest',
'autocommit': True,
}
# myproject/pyodbc_debug.py
import pyodbc
_original_connect = pyodbc.connect
def debug_connect(*args, **kwargs):
print("\n=== pyodbc.connect called ===")
print("args:", args)
print("kwargs:", kwargs)
print("================================\n")
return _original_connect(*args, **kwargs)
pyodbc.connect = debug_connect
import subprocess
def get_windows_username():
result = subprocess.run(
['cmd.exe', '/c', 'echo', '%USERNAME%'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
return result.stdout.strip()
import pyodbc
try:
conn = pyodbc.connect(
"DRIVER={ODBC Driver 18 for SQL Server};"
"SERVER=xxx.database.windows.net;"
"DATABASE=xxx;"
"UID=xxxx@aaaa.com;"
"Authentication=ActiveDirectoryInteractive;"
"Encrypt=yes;"
"TrustServerCertificate=no;"
)
except Exception as e:
print("接続エラー:", e)
import msal
import struct
# Azure AD 設定
TENANT_ID = 'your-tenant-id' # GUID形式(例: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
CLIENT_ID = 'your-client-id' # Azure AD アプリ(Public Client アプリ)で取得
USERNAME = 'your-username@yourdomain.com'
# トークンを取得する関数
def get_access_token():
app = msal.PublicClientApplication(
CLIENT_ID,
authority=f"https://login.microsoftonline.com/{TENANT_ID}"
)
scopes = ["https://database.windows.net//.default"]
result = app.acquire_token_interactive(scopes=scopes, login_hint=USERNAME)
if "access_token" in result:
return result["access_token"]
raise Exception(f"トークン取得失敗: {result.get('error_description')}")
# トークンをSQL Serverが受け取れる形式に変換(バイナリにして渡す)
access_token = get_access_token()
token_bytes = bytes(access_token, "utf-8")
token_struct = struct.pack(f"{len(token_bytes)}s", token_bytes)
# Django DATABASES 設定
DATABASES = {
'default': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'your-db-name',
'HOST': 'your-server-name.database.windows.net',
'PORT': '1433',
'USER': '', # トークン認証では空文字でOK
'PASSWORD': '', # トークン認証では空文字でOK
'OPTIONS': {
'driver': 'ODBC Driver 18 for SQL Server',
'extra_params': 'Authentication=ActiveDirectoryAccessToken',
'attrs_before': {
1256: token_struct # 1256 = SQL_COPT_SS_ACCESS_TOKEN
}
}
}
}
pip install msal django-pyodbc-azure
sudo apt install msodbcsql18
django==5.0.6
msal==1.25.0
pyodbc==5.1.0
django-mssql-backend==2.10.1
memo
双方向参照のコメントは間違いなので、
Djangoの設定やアプリ初期化前にDjangoモジュールを呼び出していることによる副作用
により、何か環境構築でミスってるのか。と思ってしまうような「ハマる」要素を誘うエラー内容でしたが
settings.pyの中で、自作のモジュールのimportをやめたら、その手のエラーがでなくなった経緯があります。
だったのが正確なところなので、
そのようなコメント記述に
import subprocess
def wslpath_w(linux_path: str) -> str:
try:
result = subprocess.run(['wslpath', '-w', linux_path], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"エラー: {e.stderr.strip()}")
return ""
def main():
linux_path = "/home/yourname/project"
windows_path = wslpath_w(linux_path)
if windows_path:
print(f"Windowsパス: {windows_path}")
else:
print("パスの変換に失敗しました。")
if __name__ == "__main__":
main()
import win32com.client
import os
import sys
def export_excel_to_pdf(excel_path, pdf_path):
excel = None
wb = None
try:
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = False
wb = excel.Workbooks.Open(excel_path)
wb.ExportAsFixedFormat(0, pdf_path)
print(f"✅ Exported to PDF: {pdf_path}")
except Exception as e:
print(f"❌ Error during export: {e}", file=sys.stderr)
raise
finally:
if wb:
wb.Close(False)
if excel:
excel.Quit()
def main():
if len(sys.argv) != 3:
print("Usage:")
print(" python excel_to_pdf.py <input_excel_path> <output_pdf_path>")
print("Example:")
print(r" python excel_to_pdf.py C:\path\to\file.xlsx C:\path\to\file.pdf")
sys.exit(1)
excel_file = sys.argv[1]
pdf_file = sys.argv[2]
if not os.path.exists(excel_file):
print(f"❌ Excel file not found: {excel_file}", file=sys.stderr)
sys.exit(1)
export_excel_to_pdf(excel_file, pdf_file)
if __name__ == "__main__":
main()
import subprocess
def run_excel_to_pdf_on_windows(excel_path, pdf_path):
windows_python = "/mnt/c/Users/yourname/AppData/Local/Programs/Python/Python311/python.exe"
script_path = "/mnt/c/scripts/excel_to_pdf.py"
result = subprocess.run(
[windows_python, script_path, excel_path, pdf_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
if result.returncode != 0:
print("❌ エラー発生:")
print(result.stderr)
else:
print("✅ 正常に完了:")
print(result.stdout)
param (
[string]$excelPath,
[string]$pdfPath
)
$excel = $null
$workbook = $null
try {
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$workbook = $excel.Workbooks.Open($excelPath)
$workbook.ExportAsFixedFormat(0, $pdfPath)
Write-Output "Export successful: $pdfPath"
exit 0
}
catch {
Write-Error "Error: $_"
exit 1
}
finally {
if ($workbook) { $workbook.Close($false) }
if ($excel) { $excel.Quit() }
}
***********************************
import subprocess
def run_excel_to_pdf_via_powershell(excel_path, pdf_path, ps1_path):
result = subprocess.run(
[
"powershell.exe",
"-ExecutionPolicy", "Bypass",
"-File", ps1_path,
"-excelPath", excel_path,
"-pdfPath", pdf_path
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
if result.returncode == 1:
print("❌ PowerShell script failed.")
print("STDOUT:", result.stdout.strip())
print("STDERR:", result.stderr.strip())
openpyxl==3.1.5
Pillow>=7.0.0
'encoding': 'cp932' # ← ここがポイント
'encoding': 'utf-8' # ← これがWSL2用
function setTriggerUI(form, value) {
// 既存の hidden input(name="triggerUI")を削除
const existing = form.querySelector('input[name="triggerUI"]');
if (existing) {
existing.remove();
}
// 新しく hidden input を作成して追加
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'triggerUI';
input.value = value;
form.appendChild(input);
}
#######################
$ cat ./.gemini/settings.json
{
// すでに他の設定があれば残したまま追記
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/udemy/mcp_koza/fs_dir",
"/udemy/mcp_koza/fs_dir2",
"/udemy/mcp_koza/restaurant"
]
},
"desktop-commander": {
"command": "npx",
"args": [
"-y",
"@wonderwhy-er/desktop-commander"
]
/* 必要なら環境変数も追加
,"env": {
"SOME_TOKEN": "xxxxx"
}
*/
},
"context7": {
"command": "npx",
"args": [
"-y",
"@upstash/context7-mcp"
]
}
}
}
#######################
1 . 前提チェック
コマンド 出れば OK 補足
lsb_release ‑rs 20.04 / 22.04 / 24.04 それ以外は同じ手順で可だが Package 名が変わる可能性
sudo add-apt-repository universe 成功 openjdk‑21‑jdk を取るのに Universe が要る
grep ^deb /etc/apt/sources.list 通常表示 Proxy 環境なら Acquire::http::Proxy の設定を先に
2 . GPG 鍵を配置(apt-secure 新方式)
bash
コピーする
編集する
sudo mkdir -p /usr/share/keyrings
公開鍵をダウンロード → .gpg 形式に変換して格納
curl -fsSL https://dbeaver.io/debs/dbeaver.gpg.key
| sudo gpg --dearmor -o /usr/share/keyrings/dbeaver.gpg
鍵の指紋を必ず確認
bash
コピーする
編集する
gpg --show-keys --with-fingerprint /usr/share/keyrings/dbeaver.gpg
| grep -A1 pub
D3 3A 1B D7 25 ED 04 7D … が表示されれば正しい鍵です
Kali Linux Forum
3 . リポジトリを追加
bash
コピーする
編集する
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/dbeaver.gpg]
https://dbeaver.io/debs/dbeaver-ce/ /"
| sudo tee /etc/apt/sources.list.d/dbeaver.list
末尾の スラッシュ / を忘れない(署名付きリポジトリと apt のバグ回避)。
この InRelease は 2025‑07‑06 に更新され、最新版 25.1.2 を含みます。
dbeaver.io
4 . パッケージ更新 & インストール
bash
コピーする
編集する
sudo apt update
Java は同梱だが、フォントの不具合を防ぐため JDK 21 を入れておく
sudo apt install openjdk-21-jdk dbeaver-ce
openjdk‑21‑jdk は 20.04/22.04/24.04 いずれも Universe に正式収録済みです。
Ask Ubuntu
DBeaver 23.0 以降は OpenJDK 21 を同梱 していますが、
システム Java があるとフォントレンダリングやクリップボード連携が安定します。
dbeaver.io
5 . 動作確認
bash
コピーする
編集する
いったんシェルを再読み込み
dbeaver &
DBeaver → Help › About で 25.1.2 と表示されればインストール完了です。
dbeaver.io
さらに SQL コンソールで
sql
コピーする
編集する
SELECT sqlite_version();
が返れば、JDBC ドライバも自動ダウンロードできるネットワーク設定になっています。
よくあるトラブルと対処
症状 原因 解決
NO_PUBKEY D33A1BD725ED047D 鍵を .gpg 形式で置いていない 2 . の gpg --dearmor をやり直す
ドライバが落ちない Proxy / TLS ミス DBeaver 上の Window › Preferences › General › Network Connections を Direct か正しい Proxy に
起動直後にクラッシュ 古い設定が残存 ~/.local/share/DBeaverData/workspace6 を一時退避して起動
まとめ
公開鍵を /usr/share/keyrings/ に .gpg 形式で置く
deb [signed‑by=…] の新方式行を追加
sudo apt update && sudo apt install dbeaver-ce だけで最新版 25.1.2 が入る
以後は sudo apt upgrade で毎月のリリースを追従可能
以上、公式リポジトリと公開鍵を直接検証した 100 % 現行手順です。
grep -R "dbeaver.io/debs" /etc/apt/sources.list.d 2>/dev/null
# ❶ まだリポジトリ鍵+dbeaver.list を作っていなければ実行
# (すでに追加済みならこの 3 行はスキップ)
curl -fsSL https://dbeaver.io/debs/dbeaver.gpg.key \
| sudo gpg --dearmor -o /usr/share/keyrings/dbeaver.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/dbeaver.gpg] \
https://dbeaver.io/debs/dbeaver-ce/ /" \
| sudo tee /etc/apt/sources.list.d/dbeaver.list
# ❷ インデックス更新
sudo apt update
# ❸ OpenJDK 21 と DBeaver 本体を一気に入れる
sudo apt install -y openjdk-21-jdk dbeaver-ce
sudo apt install openjdk-21-jdk # 先に Java だけ
sudo apt install dbeaver-ce # 後から DBeaver
// ── 親側 ──
const win = window.open('/child.html', 'myPopup'); // 名前再利用を避けたければ '' など
// ── 子側 (child.html) ──
document.addEventListener('DOMContentLoaded', () => {
const hasParent = !!window.opener && !window.opener.closed;
if (hasParent) {
// リロード後も維持できるよう sessionStorage にフラグ
sessionStorage.setItem('openedByParent', '1');
}
});
// 以降は単に:
const openedByParent = sessionStorage.getItem('openedByParent') === '1';
★★★★★★★★★★★★★★★★★★★
★★★★★★★★★★★★★★★★★★★
# views.py
import uuid
from django.http import StreamingHttpResponse, FileResponse
def download_view(request):
token = request.POST.get("dl_token") # フォームから受け取る
file_iter = my_slow_generator() # 時間のかかるストリーム
resp = StreamingHttpResponse(file_iter, content_type="application/zip")
resp["Content-Disposition"] = 'attachment; filename="bigdata.zip"'
# ★ トークンと同じ名前の Cookie を set
# header がブラウザに届いた瞬間 JS から読める
resp.set_cookie(token, "1", max_age=600, httponly=False, secure=True)
return resp
<script src="https://cdnjs.cloudflare.com/ajax/libs/uuid/8.2.0/uuid.min.js"
</script>
<form id="dl-form" action="/download/" method="post">
{% csrf_token %}
<input type="hidden" name="dl_token" id="dl_token">
<button type="submit">ダウンロード</button>
</form>
<div id="spinner" hidden>Loading...</div>
<script>
document.getElementById("dl-form").addEventListener("submit", e => {
// 1. ランダムトークンを発行
const token = crypto.randomUUID();
document.getElementById("dl_token").value = token;
// 2. スピナーを表示
document.getElementById("spinner").hidden = false;
// 3. Cookie 到着をポーリングして検知
const timer = setInterval(() => {
if (document.cookie.includes(`${token}=1`)) {
clearInterval(timer);
// 後片付け
document.cookie = `${token}=; Max-Age=0; path=/`;
document.getElementById("spinner").hidden = true;
}
}, 300); // 300 ms ごとに確認
});
</script>
Integrytyに仕込む値の取得方法
<a href="downloadHoge" id="downloadLink">hogeをダウンロード</a>
<div id="spinner" style="display: none;">スピナー表示中...</div>
<script>
document.getElementById("downloadLink").addEventListener("click", function(event) {
event.preventDefault(); // 一旦止める
// スピナー表示
document.getElementById("spinner").style.display = "block";
// 少し遅らせてからダウンロード開始(スピナーが描画される時間確保)
setTimeout(() => {
const a = document.createElement("a");
a.href = this.href;
a.style.display = "none";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
// スピナーは自動では消えない(ダウンロード完了イベントがないため)
// 必要なら手動で5秒後などに非表示化してもOK
// setTimeout(() => {
// document.getElementById("spinner").style.display = "none";
// }, 5000);
}, 100); // 少しだけ遅延
});
</script>
*********************
オンライン端末(インターネットにつながる端末)で、
pip download -r requirements.txt -d wheels/
別にvenvに入らなくても、どこでも、
どのフォルダでも、pipコマンドさえ使える場所で、
requirements.txtがあれば実行可能。
この時に、オンライン端末でこのコマンドを打ち込むフォルダで
python3 -V( windows なら、python -V か)を打ち込んだときに
表示されるバージョンと、
オフライン側の、それとバージョンが一致しておればよい
pythonの実態のパスまでが同じである必要はない
*********************
オフライン端末側で、
python -m venv .venv
.venv\Scripts\activate (windowsの直の場合)
> ちなみに、
> Git bashなら source .venv\Scripts\activate
> WSL2なら source .venv\bin\activate
にて、仮想環境にactivateした後、
pip install --no-index --find-links=.\wheels -r requirements.txt
( Git bash、WSL2の場合は、--find-links=./wheels )
--no-indexは、PyPIからのダウンロードをしないという意味
*********************
Windows 11 端末同士であれば、細かなwindowsのバージョン違うならOK
Python本体のインストール場所が違っていてもOK
cursorエディタのmcpの例
.cursor/mcp.json
{
"mcpServers": {
"context7": {
"command": "npx",
"args": [
"-y",
"@upstash/context7-mcp"
]
},
"github": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "github_pat_XXXXXXX"
}
},
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
}
}
}
dism /Online /Add-Capability /CapabilityName:Language.Basic~~~ja-JP~0.0.1.0
Set-WinDefaultInputMethodOverride -InputTip "0411:00000411"
windows環境では、
powershell 7以降の場合は、
echo $PROFILE
で表示されるパスのスクリプトに、( なければ、つくってでも )
mise activate pwsh | Out-String | Invoke-Expression
を追加する
上記は、powershell 5.1では、LocationChangedACtionが見つかりません
というエラーがでる。
powershell 5.1では、miseのactivated: yesが非対応であるため
shims_on_path: yes
にするしかない
その場合は、
powershellで、
echo $env:LOCALAPPDATA\mise\shims
した結果、表示されたパスを、
環境変数PATH に、GUIで追加したら、
恒久的に、次のpowershellのセッション以降 powershellでも、git bashでも、 mise doctorしたら、
shims_on_path: yes
になる。
shims_on_path: yes
は、ちょっと、切り替わりが遅いだけ(一般に数ミリ秒程度)で、activated: yes
と同じ使い方ができるものとのこと
aaaaa
echo 'mise activate pwsh | Out-String | Invoke-Expression' >> $HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
# Windows (Git Bash):
python -m pip wheel odfpy==1.4.1 -w wheels
# WSL2:
python3 -m pip wheel odfpy==1.4.1 -w wheels
python3 -m pip wheel odfpy==1.4.1 -w wheels
<追記>
miseが絡んだ環境をいくつか切り替えてる時
pip installでキャッシュ関連のエラーに遭遇することがある
その場合は、
を参考にしてください!!
winget install Microsoft.WinDbg
WinDbgX -c ".symfix; .sympath+ %CD%\bin; .srcpath %CD%; .lines 1; .loadby sos clr; !bpmd unitTestCSharp.exe Program::Main; g" ".\bin\unitTestCSharp.exe"
build_net48.bat
@echo off
REM .NET 4.5~4.8はCLR 4.0(v4.0.30319)のin-place更新なので csc.exe は v4.0.30319 配下のまま
setlocal
set "FW=%WINDIR%\Microsoft.NET\Framework64\v4.0.30319"
set "CSC=%FW%\csc.exe"
if not exist "%CSC%" (echo [ERROR] csc.exe not found: %CSC% & exit /b 1)
if not exist ".\bin" mkdir ".\bin"
REM 参照は Dev Pack ではなく、ランタイム側の System*.dll を直接使う
"%CSC%" /nologo /debug:full /optimize- /target:exe /out:bin\unitTestCSharp.exe ^
/r:"%FW%\System.dll" /r:"%FW%\System.Core.dll" ^
src\cs\common.cs src\cs\unitTestCSharp.cs
if errorlevel 1 (echo [BUILD FAILED] & exit /b 1)
echo [BUILD OK] bin\unitTestCSharp.exe と PDB を作成
echo WinDbg 起動例: WinDbgX "%CD%\bin\unitTestCSharp.exe"
endlocal
winget uninstall --id Microsoft.WinDbg -e
winget uninstall --id Microsoft.WinDbg -e --source winget
winget list WinDbg
if not exist bin mkdir bin & "%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe" /nologo /debug:full /optimize- /target:exe /out:bin\unitTestCSharp.exe /pdb:bin\unitTestCSharp.pdb /r:"%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\System.dll" /r:"%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\System.Core.dll" src\cs\common.cs src\cs\unitTestCSharp.cs
@echo off
REM build_net48_dbg.bat
REM 4.5~4.8 は CLR 4.0(v4.0.30319)へ“in-place更新”。よって csc.exe は v4.0.30319 配下。
REM ★ bin フォルダは「ある前提」。作成しない。
set "FW=%WINDIR%\Microsoft.NET\Framework64\v4.0.30319"
set "OUT=bin\unitTestCSharp.exe"
set "PDB=bin\unitTestCSharp.pdb"
set "RSP=%CD%\csc_args.rsp"
REM ── csc のレスポンスファイルを作る(行継続や ^ を使わず安全)
> "%RSP%" echo /nologo
>>"%RSP%" echo /debug:full
>>"%RSP%" echo /optimize-
>>"%RSP%" echo /target:exe
>>"%RSP%" echo /out:%OUT%
>>"%RSP%" echo /pdb:%PDB%
>>"%RSP%" echo /langversion:latest
>>"%RSP%" echo /define:TRACE;DEBUG
>>"%RSP%" echo /nostdlib+
>>"%RSP%" echo /r:"%FW%\mscorlib.dll"
>>"%RSP%" echo /r:"%FW%\System.dll"
>>"%RSP%" echo /r:"%FW%\System.Core.dll"
>>"%RSP%" echo /r:"%FW%\Microsoft.CSharp.dll"
REM ── コンパイル(src\cs\common.cs と src\cs\unitTestCSharp.cs のみ)
"%FW%\csc.exe" @"%RSP%" src\cs\common.cs src\cs\unitTestCSharp.cs
if errorlevel 1 (
echo [BUILD FAILED]
exit /b 1
)
echo [BUILD OK] %OUT% と PDB を作成
echo WinDbg 例: WinDbgX "%CD%\%OUT%"
.NET Framework 4.8.09032
は、
C# 5まで、利用可であります
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe
Discussion